The result is a view, never a fresh buffer. For UNCOMPRESSED it is
data itself — the page's own bytes inside the file, handed back
untouched, which is what SerializedPageReader::DecompressIfNeeded
does in parquet-cpp. For every other codec it is scratch, the
caller's one decompression buffer per column chunk, grown in place and
never shrunk — parquet-cpp's decompression_buffer_, resized with
shrink_to_fit=false (column_reader.cc:564).
Lifetime contract — the span is valid only until the next call that
passes the same scratch. That call overwrites the buffer and may
reallocate it, so a span held across a page boundary reads another
page's bytes. parquet-cpp documents the same rule at
column_reader.cc:251: the previous page is invalidated by
NextPage(). Copy out anything that has to outlive the page —
decode_plain_into and its neighbours already do, which is why a
dictionary page survives the data pages decompressed after it.
Mojo's origins cannot make the compiler enforce that. The returned
origin is the union of the file's and the scratch buffer's, so both are
kept alive for as long as the span is and it can never dangle, but Mojo
does not treat an outstanding immutable view as blocking a later
mutation the way an exclusivity checker would — a held span is a wrong
answer, not a compile error. So the rule is a contract, and
test_a_page_span_is_only_valid_until_the_next_page is what states it.
uncompressed_size is the page header's declared decompressed length,
which for Brotli and raw LZ4 is the only size there is.