Skip to main content

BufferReader

Struct BufferReader 

Source
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>

Source

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.

Source

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.

Source

pub fn read_int(&self, field_name: &str) -> Result<i64, BufferError>

Read a 64-bit signed integer from field_name.

Source

pub fn read_float(&self, field_name: &str) -> Result<f64, BufferError>

Read a 64-bit float from field_name.

Source

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).

Source

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.

Source

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.

Source

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.
Source

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.

Source

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].

Source

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.

Source

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.

Source

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).

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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§

Source§

impl<'a> Debug for BufferReader<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.