pub fn merge_table_list<'a, T, V, B, FA, FB>(
views: &'a [V],
out: &mut B,
get_list: FA,
get_block_end: FB,
) -> usizewhere
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 i64Slots 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.