use crate::buffer::Buffer;
use crate::read::{HasRawView, ListView, ReadAt};
use crate::serialize::{Serialize, SerializeBytes};
#[inline]
pub fn merge_inline_list<'a, T, V, B, F>(
views: &'a [V],
out: &mut B,
elem_size: usize, align_mask: usize, get_list: F, ) -> usize
where
B: Buffer,
T: ReadAt<'a>,
F: Fn(&'a V) -> ListView<'a, T>,
{
let total_bytes: usize = views.iter()
.map(|v| get_list(v).len() * elem_size)
.sum();
if total_bytes == 0 { return 0; }
out.ensure_capacity(total_bytes + align_mask);
*out.head_mut() -= total_bytes;
*out.head_mut() &= !align_mask;
let base = out.head();
let mut pos = base;
for v in views.iter().rev() {
let list = get_list(v);
if list.is_empty() { continue; }
let block = list.len() * elem_size;
out.buffer_mut()[pos..pos + block]
.copy_from_slice(&list.buf[list.offset..list.offset + block]);
pos += block;
}
let total_len = (total_bytes / elem_size) as u32;
total_len.write_to_unchecked(out)
}
#[inline]
pub fn merge_string_list<'a, V, B, F>(
views: &'a [V],
out: &mut B,
get_list: F,
) -> usize
where
B: Buffer,
F: Fn(&'a V) -> ListView<'a, String>,
{
use crate::read::ReadAt as _;
let mut pool_starts: Vec<usize> = Vec::with_capacity(views.len());
let mut total_len = 0u32;
for v in views.iter() {
let list = get_list(v);
if list.is_empty() { pool_starts.push(0); continue; }
let n = list.len();
let pool_start = list.offset + n * 4;
let last = list.last_offset();
let pool_end = last + 4 + u32::read_at(list.buf, last) as usize;
let pool_size = pool_end - pool_start;
out.ensure_capacity(pool_size + 3);
*out.head_mut() -= pool_size;
*out.head_mut() &= !3;
let h = out.head();
out.buffer_mut()[h..h + pool_size]
.copy_from_slice(&list.buf[pool_start..pool_end]);
pool_starts.push(h);
total_len += n as u32;
}
for (v, &dest_pool_start) in views.iter().zip(pool_starts.iter()) {
let list = get_list(v);
if list.is_empty() { continue; }
let n = list.len();
let jump_size = n * 4;
let delta = dest_pool_start as i64 - out.head() as i64;
out.ensure_capacity(jump_size + 3);
*out.head_mut() -= jump_size;
*out.head_mut() &= !3;
let dst_h = out.head();
out.buffer_mut()[dst_h..dst_h + jump_size]
.copy_from_slice(&list.buf[list.offset..list.offset + jump_size]);
for j in 0..n {
let p = dst_h + j * 4;
let v = u32::read_at(out.buffer(), p) as i64;
out.buffer_mut()[p..p + 4]
.copy_from_slice(&((v + delta) as u32).to_le_bytes());
}
}
if total_len == 0 { 0 } else { total_len.write_to_unchecked(out) }
}
#[inline]
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::ReadOutput: HasRawView<'a>,
FA: Fn(&'a V) -> ListView<'a, T>,
FB: Fn(&T::ReadOutput) -> usize,
{
use crate::read::ReadAt as _;
let mut vt_map: Vec<(Vec<u8>, usize)> = Vec::new();
for v in views.iter() {
let lst = get_list(v);
for j in 0..lst.len() {
let el = lst.get(j);
let raw = el.raw_view();
let vp = raw.v_pos;
let vs = u16::read_at(raw.buf, vp) as usize;
let vb = &raw.buf[vp..vp + vs];
if !vt_map.iter().any(|(b, _)| b.as_slice() == vb) {
let s = SerializeBytes::write_bytes_to(&vb, out);
vt_map.push((vb.to_vec(), s));
}
}
}
let mut elem_slots: Vec<usize> = Vec::new();
let mut total_len = 0u32;
for v in views.iter() {
let lst = get_list(v);
let n = lst.len();
for j in (0..n).rev() {
let el = lst.get(j);
let raw = el.raw_view();
let tp = raw.t_pos;
let obj_end = tp + u16::read_at(raw.buf, raw.v_pos + 2) as usize;
let be = get_block_end(&el).max(obj_end);
let blen = be - tp;
out.ensure_capacity(blen);
*out.head_mut() -= blen;
let dst = out.head();
out.buffer_mut()[dst..dst + blen]
.copy_from_slice(&raw.buf[tp..be]);
let vp = raw.v_pos;
let vs = u16::read_at(raw.buf, vp) as usize;
let vb = &raw.buf[vp..vp + vs];
let vt_slot = vt_map.iter()
.find(|(b, _)| b.as_slice() == vb)
.map(|(_, s)| *s)
.unwrap();
let new_vt_abs = out.len() - vt_slot;
let new_jump = (dst as i64 - new_vt_abs as i64) as i32;
out.buffer_mut()[dst..dst + 4]
.copy_from_slice(&new_jump.to_le_bytes());
elem_slots.push(out.slot());
}
total_len += n as u32;
}
for tgt_slot in &elem_slots {
out.ensure_capacity(7);
*out.head_mut() -= 4;
*out.head_mut() &= !3;
let h = out.head();
let jump = (out.slot() - tgt_slot) as u32;
out.buffer_mut()[h..h + 4].copy_from_slice(&jump.to_le_bytes());
}
if total_len == 0 { 0 } else { total_len.write_to_unchecked(out) }
}
#[inline(always)]
pub fn write_union_slot<B: Buffer>(buffer: &mut B, data_slot: usize, tag: u8) -> usize {
*buffer.head_mut() -= 5;
*buffer.head_mut() &= !3;
let head = buffer.head();
let jump = (buffer.slot() - data_slot) as u32;
buffer.buffer_mut()[head..head + 4].copy_from_slice(&jump.to_le_bytes());
buffer.buffer_mut()[head + 4] = tag;
buffer.slot()
}
#[inline]
pub fn merge_union_list<'a, T, V, B, F>(
views: &'a [V],
out: &mut B,
get_list: F,
) -> usize
where
B: Buffer,
T: ReadAt<'a>,
T::ReadOutput: crate::serialize::Serialize,
F: Fn(&'a V) -> ListView<'a, T>,
{
use crate::read::ReadAt as _;
use crate::serialize::Serialize as _;
let total_n: usize = views.iter().map(|v| get_list(v).len()).sum();
if total_n == 0 { return 0; }
let mut slots: Vec<usize> = Vec::with_capacity(total_n);
let mut tags: Vec<u8> = Vec::with_capacity(total_n);
for v in views.iter() {
let list = get_list(v);
let n = list.len();
for j in (0..n).rev() {
let tag = u8::read_at(list.buf, list.offset + 4 * n + j);
let slot = if tag != 0 {
list.get(j).write_to(out) } else {
0
};
slots.push(slot);
tags.push(tag);
}
}
*out.head_mut() &= !3;
let pad = (4usize.wrapping_sub(total_n & 3)) & 3;
out.ensure_capacity(pad + total_n + total_n * 4 + 7);
*out.head_mut() -= pad;
for &tag in tags.iter() {
*out.head_mut() -= 1;
let h = out.head();
out.buffer_mut()[h] = tag;
}
for &target_slot in slots.iter() {
*out.head_mut() -= 4;
let h = out.head();
let jump = if target_slot == 0 { 0u32 }
else { (out.slot() - target_slot) as u32 };
out.buffer_mut()[h..h + 4].copy_from_slice(&jump.to_le_bytes());
}
(total_n as u32).write_to_unchecked(out)
}
#[inline]
pub fn merge_file_list<'a, T, V, B, F>(
views: &'a [V],
out: &mut B,
get_list: F,
) -> usize
where
B: Buffer,
T: ReadAt<'a>,
F: Fn(&'a V) -> ListView<'a, T>,
{
use crate::read::ReadAt as _;
let mut pool_starts: Vec<usize> = Vec::with_capacity(views.len());
let mut total_len = 0u32;
for v in views.iter() {
let list = get_list(v);
if list.is_empty() { pool_starts.push(0); continue; }
let n = list.len();
let pool_start = list.offset + n * 4;
let last = list.last_offset();
let pool_end = last + 4 + u32::read_at(list.buf, last) as usize;
let pool_size = pool_end - pool_start;
out.ensure_capacity(pool_size + 3);
*out.head_mut() -= pool_size;
*out.head_mut() &= !3;
let h = out.head();
out.buffer_mut()[h..h + pool_size]
.copy_from_slice(&list.buf[pool_start..pool_end]);
pool_starts.push(h);
total_len += n as u32;
}
for (v, &dest_pool_start) in views.iter().zip(pool_starts.iter()) {
let list = get_list(v);
if list.is_empty() { continue; }
let n = list.len();
let jump_size = n * 4;
let delta = dest_pool_start as i64 - out.head() as i64;
out.ensure_capacity(jump_size + 3);
*out.head_mut() -= jump_size;
*out.head_mut() &= !3;
let dst_h = out.head();
out.buffer_mut()[dst_h..dst_h + jump_size]
.copy_from_slice(&list.buf[list.offset..list.offset + jump_size]);
for j in 0..n {
let p = dst_h + j * 4;
let v = u32::read_at(out.buffer(), p) as i64;
out.buffer_mut()[p..p + 4]
.copy_from_slice(&((v + delta) as u32).to_le_bytes());
}
}
if total_len == 0 { 0 } else { total_len.write_to_unchecked(out) }
}