Skip to main content

merge_table_list

Function merge_table_list 

Source
pub fn merge_table_list<'a, T, V, B, FA, FB>(
    views: &'a [V],
    out: &mut B,
    get_list: FA,
    get_block_end: FB,
) -> usize
where B: Buffer, T: ReadAt<'a>, <T as ReadAt<'a>>::ReadOutput: HasRawView<'a>, FA: Fn(&'a V) -> ListView<'a, T>, FB: Fn(&<T as ReadAt<'a>>::ReadOutput) -> usize,
Expand description

Merge a List(Table) field using three-pass block copying.

§Layout of a table element in the source buffer

[vtable_jump: i32][field_0][field_1]...  ← table object at t_pos
[vtable_size: u16][object_size: u16][voff_0: u16]...  ← vtable at v_pos
[nested payload (strings, arrays, nested tables)]

The entire block from t_pos to block_end() is self-contained: all internal offsets are relative to positions within the block and survive a verbatim copy_from_slice. The only external reference is the vtable jump at t_pos, which points outside the block to a (potentially shared) vtable.

§Algorithm

Pass A — scan all elements across all views, write each unique vtable exactly once into the new buffer. In practice all elements of the same list type share one vtable, so this is typically one write total. Builds a vtable_bytes → slot map for use in Pass B.

Pass B — for each element: copy_from_slice the block, then rewrite the vtable jump at byte 0 of the block:

new_jump = dst as i64 - (out.len() - vt_slot) as i64

Slots are invariant under grow(), so out.len() - vt_slot always gives the correct absolute position of the vtable in the post-grow buffer.

Write order is: views forward, elements reversed within each view — this matches the general serialization path so ListView read order is identical.

Pass C — write the forward-offset table (n × u32) that ListView uses to locate each element.

§Nested tables

Any nested table fields whose data lives inside the block (reachable via a forward offset from the table object) are also copied verbatim. Their internal offsets are self-relative and survive the copy. If a nested table has its own vtable jump pointing outside the block, an additional fixup pass would be needed — the current schema (BrandData, ImageFile, Tags) has no such fields, so one fixup at t_pos suffices.

§Returns

The slot of the length-prefix u32, or 0 if all views were empty.