pub struct BufferReader<'a> { /* private fields */ }Expand description
Type-checked reader over a record buffer plus optional tail area.
The buffer is borrowed (no copy), so inline reads cost a bounds
check plus a from_le_bytes. Pointer-indirect reads follow the
u32 slot through to the tail-area [len: u32 LE][payload]
record, validating the bounds and (for String) the utf-8 bytes
against the borrowed buffer.
Implementations§
Source§impl<'a> BufferReader<'a>
impl<'a> BufferReader<'a>
Sourcepub fn new(
layout: &'a OffsetTable,
fields: &[Field],
bytes: &'a [u8],
) -> Result<Self, BufferError>
pub fn new( layout: &'a OffsetTable, fields: &[Field], bytes: &'a [u8], ) -> Result<Self, BufferError>
Build a reader over bytes interpreting it under layout.
Returns BufferError::BufferTooSmall when bytes is shorter
than layout.root_size — every leaf read otherwise would have
to repeat the same bounds check, so we do it once at
construction.
Sourcepub fn new_at_base(
layout: &'a OffsetTable,
fields: &[Field],
bytes: &'a [u8],
record_base: usize,
) -> Result<Self, BufferError>
pub fn new_at_base( layout: &'a OffsetTable, fields: &[Field], bytes: &'a [u8], record_base: usize, ) -> Result<Self, BufferError>
Build a reader whose root record’s fixed area is anchored at the
arena-absolute offset record_base inside the whole-arena slice
bytes, rather than at offset 0.
This is the F1 object-return decode entry point: under the
arena-absolute slot convention the object head lives at out_ptr
and every pointer slot it carries holds an arena-absolute offset,
so the reader walks the whole arena (bytes) and each field
slot is read at record_base + fo.offset. Mirrors the per-entry
field-index rebase Self::read_list_record_at /
Self::sub_record already perform, so a subsequent
pointer-indirect read resolves its arena-absolute slot value
directly against bytes.
Sourcepub fn read_int(&self, field_name: &str) -> Result<i64, BufferError>
pub fn read_int(&self, field_name: &str) -> Result<i64, BufferError>
Read a 64-bit signed integer from field_name.
Sourcepub fn read_float(&self, field_name: &str) -> Result<f64, BufferError>
pub fn read_float(&self, field_name: &str) -> Result<f64, BufferError>
Read a 64-bit float from field_name.
Sourcepub fn read_bool(&self, field_name: &str) -> Result<bool, BufferError>
pub fn read_bool(&self, field_name: &str) -> Result<bool, BufferError>
Read a boolean from field_name. Any non-zero byte decodes
as true (the layout only writes 0 or 1, but defensive
decoding makes the reader robust against buffer corruption).
Sourcepub fn read_unit(&self, field_name: &str) -> Result<(), BufferError>
pub fn read_unit(&self, field_name: &str) -> Result<(), BufferError>
Confirm field_name is declared as an internal unit slot and that the slot
is reachable. The byte value is unused (Unit slots are
tag-only), so this only validates the type label.
Sourcepub fn read_value(
&self,
field_name: &str,
ty: &TypeRepr,
) -> Result<Value, BufferError>
pub fn read_value( &self, field_name: &str, ty: &TypeRepr, ) -> Result<Value, BufferError>
Read any supported value shape from field_name using its canonical
type. Mirrors BufferBuilder::write_value.
Sourcepub fn read_string(&self, field_name: &str) -> Result<&'a str, BufferError>
pub fn read_string(&self, field_name: &str) -> Result<&'a str, BufferError>
Read a UTF-8 string from field_name. Follows the fixed-area
u32 pointer into the tail area, validates the length prefix
- payload bounds, and decodes the bytes as utf-8.
Sourcepub fn read_list_int(&self, field_name: &str) -> Result<Vec<i64>, BufferError>
pub fn read_list_int(&self, field_name: &str) -> Result<Vec<i64>, BufferError>
Read a List<Int> from field_name. Follows the fixed-area
u32 pointer into the tail area and copies the i64 elements
into a fresh Vec<i64> so callers don’t have to wrestle with
alignment of the borrowed slice.
Sourcepub fn read_list_float(&self, field_name: &str) -> Result<Vec<f64>, BufferError>
pub fn read_list_float(&self, field_name: &str) -> Result<Vec<f64>, BufferError>
Read a List<Float> from field_name. Tail layout mirrors
List<Int> — [len: u32][pad to 8][f64 elements].
Sourcepub fn read_list_bool(&self, field_name: &str) -> Result<Vec<bool>, BufferError>
pub fn read_list_bool(&self, field_name: &str) -> Result<Vec<bool>, BufferError>
Read a List<Bool> from field_name. Tail layout [len: u32] [u8 booleans]. Non-zero bytes decode as true — defensive,
the writer always emits 0 / 1.
Sourcepub fn read_list_string(
&self,
field_name: &str,
) -> Result<Vec<&'a str>, BufferError>
pub fn read_list_string( &self, field_name: &str, ) -> Result<Vec<&'a str>, BufferError>
Read a List<String> from field_name. Walks the pointer
array, then decodes each per-entry [len: u32][bytes] record
as UTF-8 borrowed from the underlying buffer.
Sourcepub fn read_list_string_at(
&self,
header_off: usize,
) -> Result<Vec<&'a str>, BufferError>
pub fn read_list_string_at( &self, header_off: usize, ) -> Result<Vec<&'a str>, BufferError>
Read a List<String> whose pointer-array header sits directly
at header_off (rather than behind a named fixed-area slot). This
is the in-place region-walk return entry point (S3): the machine
code reports the arena-relative offset of the outer
[len][off_0]…[off_{N-1}] header, the host rebases it to
header_off, and — after the verifier certifies the whole graph
stays in-region — this walks the same bytes [read_list_string]
would, so a top-level (field-slot) and an in-place decode of the
same buffer are byte-identical, including each string’s content.
Every offset / length is bounds-checked against the buffer end
before any read (the verifier already proved the tighter
single-region bound); a non-UTF-8 payload is a loud error, matching
[read_list_string] and the Value::String invariant (Relon
strings are always valid UTF-8).
Sourcepub fn read_list_record<'b>(
&self,
field_name: &str,
elem_layout: &'b OffsetTable,
elem_schema: &'b Schema,
) -> Result<Vec<BufferReader<'a>>, BufferError>where
'b: 'a,
pub fn read_list_record<'b>(
&self,
field_name: &str,
elem_layout: &'b OffsetTable,
elem_schema: &'b Schema,
) -> Result<Vec<BufferReader<'a>>, BufferError>where
'b: 'a,
Read a List<Schema> from field_name. Returns a vector of
BufferReaders, one per entry, each anchored at the
matching sub-record’s fixed area. The readers share the parent
buffer slice so subsequent String / Int / Schema reads through
them resolve back into the same tail area.
Sourcepub fn read_list_record_at<'b>(
&self,
header_off: usize,
elem_layout: &'b OffsetTable,
elem_schema: &'b Schema,
) -> Result<Vec<BufferReader<'a>>, BufferError>where
'b: 'a,
pub fn read_list_record_at<'b>(
&self,
header_off: usize,
elem_layout: &'b OffsetTable,
elem_schema: &'b Schema,
) -> Result<Vec<BufferReader<'a>>, BufferError>where
'b: 'a,
Read a List<Schema> whose outer pointer-array header sits
directly at header_off (a region-relative offset into
self.bytes), rather than being reached through a record’s
fixed-area slot.
This is the reader half of the in-place region-walk return ABI
(S4). The machine code returns the arena-absolute offset of the
root list header [len][off_0]…[off_{N-1}]; the host rebases it to
a region-relative offset, runs crate::verifier::verify_value_at
over the whole reachable graph (outer entries → each sub-record’s
fixed area → every String / List field pointer the sub-record
carries), and only then calls this to decode in place. Each entry
pointer names a sub-record anchored at elem_layout; a
BufferReader is produced per entry sharing the same buffer
slice, so subsequent field reads (read_string, read_list_int,
…) resolve back into the same tail area — bit-identical to the
field-slot Self::read_list_record path the tree-walk oracle’s
writer feeds.
Sourcepub fn read_list_value_at(
&self,
header_off: usize,
element: &TypeRepr,
) -> Result<Vec<Value>, BufferError>
pub fn read_list_value_at( &self, header_off: usize, element: &TypeRepr, ) -> Result<Vec<Value>, BufferError>
Recursively decode a List<element> whose header sits directly
at header_off (a region-relative offset into self.bytes) into
a Vec<Value>, dispatching on the declared element type. This is
the unified in-place list reader behind the F5 doubly-nested
pointer-array shapes (List<List<String>> / List<List<Schema>>):
the outer call reads the outer pointer array, and each entry —
being itself a List<inner> — recurses one level deeper, exactly
the depth the verifier already certified. Every offset / length is
bounds-checked against self.bytes; a non-UTF-8 String payload is a
loud error. The produced values are bit-identical to the field-slot
readers the tree-walk oracle’s writer feeds.
Sourcepub fn read_list_value(
&self,
field_name: &str,
element: &TypeRepr,
) -> Result<Vec<Value>, BufferError>
pub fn read_list_value( &self, field_name: &str, element: &TypeRepr, ) -> Result<Vec<Value>, BufferError>
Field-slot entry point for the recursive list reader: resolve the
pointer-indirect field_name slot to its list header offset, then
decode through Self::read_list_value_at. element is the
outer list’s element type. Used by the object / sub-record decode
path so a List<List<String|Schema>> field decodes to the same
Vec<Value> the in-place return path produces.
Sourcepub fn read_list_list(
&self,
field_name: &str,
) -> Result<Vec<Vec<Value>>, BufferError>
pub fn read_list_list( &self, field_name: &str, ) -> Result<Vec<Vec<Value>>, BufferError>
Read a List<List<scalar>> from field_name as a vector of
inner Vec<Value>s. The outer slot points at a pointer-array
header [len][off_0]…[off_{N-1}] whose entries name per-element
inner records [len: u32][pad to inner_align][payload] — exactly
what write_nested_scalar_list / write_list_list_with emit.
Each inner record is decoded per the innermost scalar type
(Int / Float / Bool); inner pointer-array elements
(List<List<String>> / List<List<Schema>>) are rejected by the
layout pass before any buffer is produced, so they never reach
here and are surfaced as a hard error if they somehow do.
The walk is the reader-side mirror of the writer and shares the
same single buffer base: every off_i and inner [len] prefix is
resolved against self.bytes, so a sub-reader produced by
Self::read_list_record / Self::sub_record (which re-bases
the field index but keeps the same bytes slice) decodes a nested
list field bit-identically to a top-level one.
Sourcepub fn read_list_list_at(
&self,
header_off: usize,
inner: &TypeRepr,
) -> Result<Vec<Vec<Value>>, BufferError>
pub fn read_list_list_at( &self, header_off: usize, inner: &TypeRepr, ) -> Result<Vec<Vec<Value>>, BufferError>
Decode a List<List<scalar>> value whose outer pointer-array
header sits at header_off (a direct offset into self.bytes),
rather than being reached through a record’s fixed-area slot.
This is the reader half of the in-place region-walk return ABI
(S1). The machine code returns the arena-absolute offset of the
root list header; the host rebases it to a region-relative offset,
runs crate::verifier::verify_value_at over the whole reachable
graph, and only then calls this to decode in place. inner is the
innermost scalar element type (Int / Float / Bool) drained
from the return layout. The decode shares
Self::decode_list_list_rows with the field-slot
Self::read_list_list path, so a top-level and an in-place
decode of the same bytes are bit-identical.
Sourcepub fn sub_record(
&self,
field_name: &str,
sub_layout: &'a OffsetTable,
sub_fields: &[Field],
) -> Result<BufferReader<'a>, BufferError>
pub fn sub_record( &self, field_name: &str, sub_layout: &'a OffsetTable, sub_fields: &[Field], ) -> Result<BufferReader<'a>, BufferError>
Decode the buffer-relative pointer slot for a nested branded
dict field. Returns a fresh BufferReader anchored at the
sub-record’s fixed-area base, sharing the parent’s underlying
byte buffer.
Phase 3.b: branded dict fields lay their fixed area in the
parent’s tail area, addressed through a 4-byte pointer slot in
the parent’s fixed area. The sub-record’s own pointer-indirect
children (its String / List<Int> / nested Dict slots) keep
pointing into the same shared buffer — sub_record borrows the
parent bytes verbatim, so a subsequent read_string on the
sub-reader resolves through the same tail area without copying.
sub_layout is the OffsetTable for the sub-schema (e.g.
computed via crate::layout::SchemaLayout::offsets_for).
sub_fields is the schema-declared field list — pass
sub_schema.fields.as_slice() so the returned reader can
type-check its own field accesses.
Trait Implementations§
Auto Trait Implementations§
impl<'a> Freeze for BufferReader<'a>
impl<'a> RefUnwindSafe for BufferReader<'a>
impl<'a> Send for BufferReader<'a>
impl<'a> Sync for BufferReader<'a>
impl<'a> Unpin for BufferReader<'a>
impl<'a> UnsafeUnpin for BufferReader<'a>
impl<'a> UnwindSafe for BufferReader<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more