use super::sizes::{LENGTH_RESERVED, ONE_BYTE_MAX, VARINT_MAX_BYTES};
use super::{floats, lanes};
use crate::binary::table::interner::Interner;
use crate::binary::writer::START_BYTES;
use crate::binary::{Writer, varint, zigzag};
use crate::schema::Schema;
pub fn to_frame<T: Schema>(v: &T) -> Vec<u8> {
let mut p = Packer::new();
v.pack(&mut p);
p.finish()
}
#[derive(Debug)]
pub struct Packer {
out: Vec<u8>,
table: Vec<u8>,
strings: Interner,
}
impl Default for Packer {
fn default() -> Self {
Self::new()
}
}
impl Packer {
#[must_use]
pub fn new() -> Self {
Packer {
out: Vec::with_capacity(START_BYTES),
table: Vec::new(),
strings: Interner::new(),
}
}
pub fn put_u(&mut self, n: u64) {
varint(&mut self.out, n);
}
pub fn put_i(&mut self, n: i64) {
varint(&mut self.out, zigzag(n));
}
pub fn put_bool(&mut self, b: bool) {
self.out.push(u8::from(b));
}
pub fn put_f64(&mut self, f: f64) {
self.out.extend_from_slice(&f.to_le_bytes());
}
pub fn put_f32(&mut self, f: f32) {
self.out.extend_from_slice(&f.to_le_bytes());
}
pub fn put_f64s(&mut self, items: &[f64]) {
self.put_u(items.len() as u64);
let narrow = floats::fits_f32(items);
self.put_bool(narrow);
if narrow {
floats::put_narrow(&mut self.out, items);
} else {
floats::put_wide(&mut self.out, items);
}
}
pub fn put_uints(&mut self, len: usize, items: impl Iterator<Item = u64> + Clone) {
self.put_u(len as u64);
let max = items.clone().fold(0, u64::max);
let bits = (u64::BITS - max.leading_zeros()).max(1);
self.out.push(u8::try_from(bits).unwrap_or(u8::MAX));
lanes::pack(&mut self.out, len, bits, items);
}
pub fn put_f32s(&mut self, items: &[f32]) {
self.put_u(items.len() as u64);
floats::put_f32s(&mut self.out, items);
}
pub fn put_str(&mut self, s: &str) {
let i = match self.strings.lookup(&self.table, s) {
Ok(i) => i,
Err(hash) => {
varint(&mut self.table, s.len() as u64);
let at = self.table.len();
self.table.extend_from_slice(s.as_bytes());
self.strings.add(&self.table, s, at, hash)
}
};
self.put_u(i as u64);
}
pub fn put_bytes(&mut self, b: &[u8]) {
self.put_u(b.len() as u64);
self.out.extend_from_slice(b);
}
pub fn put_tagged<T: Schema>(&mut self, v: &T) {
let mut w = Writer::body();
v.encode(&mut w);
self.put_bytes(&w.finish());
}
pub fn begin(&mut self) -> usize {
let at = self.out.len();
self.out.extend_from_slice(&[0; LENGTH_RESERVED]);
at
}
pub fn begin_list(&mut self, len: usize) -> usize {
self.put_u(len as u64);
self.begin()
}
pub fn end(&mut self, at: usize) {
let len = self.out.len() - at - LENGTH_RESERVED;
if let Ok(byte) = u8::try_from(len)
&& len <= ONE_BYTE_MAX
{
self.out[at] = byte;
return;
}
let end = self.out.len();
varint(&mut self.out, len as u64);
let mut length = [0; VARINT_MAX_BYTES];
let used = self.out.len() - end;
length[..used].copy_from_slice(&self.out[end..]);
self.out.truncate(end);
self.out.splice(at..=at, length[..used].iter().copied());
}
#[must_use]
pub fn finish(mut self) -> Vec<u8> {
self.seal();
self.out
}
fn seal(&mut self) {
let table_len = self.table.len();
self.out.extend_from_slice(&self.table);
let at = self.out.len();
varint(&mut self.out, table_len as u64);
self.out[at..].reverse();
}
pub fn with_frame<T: Schema, R>(&mut self, v: &T, f: impl FnOnce(&[u8]) -> R) -> R {
self.clear();
v.pack(self);
self.seal();
let out = f(&self.out);
self.clear();
out
}
fn clear(&mut self) {
self.out.clear();
self.table.clear();
self.strings.clear();
}
}