pub mod floats;
pub mod lanes;
mod shaped;
mod view;
pub use shaped::{read_shaped, unpack_shaped};
pub use view::{Floats, FromF64, Ints, List, ListIter, View, list, read_view};
use yog_sync::Arc;
use bumpalo::Bump;
use crate::binary::interner::Interner;
use crate::binary::writer::START_BYTES;
use crate::binary::{
Decoder, MAX_DEPTH, VARINT_BITS, VARINT_MAX_SHIFT, VARINT_MORE, VARINT_SHIFT, Writer,
read_varint, unzigzag, varint, zigzag,
};
use crate::schema::{Schema, read_ref_value};
const F64_BYTES: usize = 8;
const F32_BYTES: usize = 4;
const LENGTH_RESERVED: usize = 1;
const ONE_BYTE_MAX: usize = 0x7F;
const INLINE_STRINGS: usize = 16;
pub fn to_frame<T: Schema>(v: &T) -> Vec<u8> {
let mut p = Packer::new();
v.pack(&mut p);
p.finish()
}
thread_local! {
static PACKER: std::cell::RefCell<Packer> = std::cell::RefCell::new(Packer::new());
}
pub fn with_frame<T: Schema, R>(v: &T, f: impl FnOnce(&[u8]) -> R) -> R {
PACKER.with(|cell| match cell.try_borrow_mut() {
Ok(mut p) => {
p.clear();
v.pack(&mut p);
let p = &mut *p;
p.seal();
let out = f(&p.out);
p.out.clear();
out
}
Err(_) => f(&to_frame(v)),
})
}
pub fn read_frame<T: Schema>(bytes: &[u8]) -> Option<T> {
let mut u = Unpacker::open(bytes)?;
let v = T::unpack(&mut u)?;
u.at_end().then_some(v)
}
pub struct Packer {
out: Vec<u8>,
table: Vec<u8>,
strings: Interner,
}
impl Default for Packer {
fn default() -> Self {
Self::new()
}
}
impl Packer {
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(bits as u8);
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.find(&self.table, s) {
Some(i) => i,
None => {
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)
}
};
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 len <= ONE_BYTE_MAX {
self.out[at] = len as u8;
return;
}
let mut length = Vec::new();
varint(&mut length, len as u64);
self.out.splice(at..at + LENGTH_RESERVED, length);
}
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();
}
fn clear(&mut self) {
self.out.clear();
self.table.clear();
self.strings.clear();
}
}
pub struct Unpacker<'b> {
body: &'b [u8],
i: usize,
table: &'b [u8],
table_at: usize,
strings: Strings<'b>,
shared: Vec<Option<Arc<str>>>,
depth: usize,
}
struct Strings<'b> {
inline: [&'b str; INLINE_STRINGS],
len: usize,
spill: Vec<&'b str>,
}
impl<'b> Strings<'b> {
fn new() -> Self {
Strings {
inline: [""; INLINE_STRINGS],
len: 0,
spill: Vec::new(),
}
}
fn len(&self) -> usize {
self.len
}
fn push(&mut self, s: &'b str) {
match self.inline.get_mut(self.len) {
Some(slot) => *slot = s,
None => self.spill.push(s),
}
self.len += 1;
}
fn get(&self, i: usize) -> Option<&'b str> {
if i >= self.len {
return None;
}
Some(if i < INLINE_STRINGS {
self.inline[i]
} else {
self.spill[i - INLINE_STRINGS]
})
}
}
impl<'b> Unpacker<'b> {
pub fn open(bytes: &'b [u8]) -> Option<Self> {
let (table_len, trailer) = read_varint_back(bytes)?;
let body_end = bytes.len().checked_sub(trailer)?.checked_sub(table_len)?;
Some(Unpacker {
body: &bytes[..body_end],
i: 0,
table: &bytes[body_end..bytes.len() - trailer],
table_at: 0,
strings: Strings::new(),
shared: Vec::new(),
depth: 0,
})
}
pub fn at_end(&self) -> bool {
self.i == self.body.len()
}
fn take(&mut self, len: usize) -> Option<&'b [u8]> {
let end = self.i.checked_add(len).filter(|&e| e <= self.body.len())?;
let out = &self.body[self.i..end];
self.i = end;
Some(out)
}
pub fn get_u(&mut self) -> Option<u64> {
read_varint(self.body, &mut self.i)
}
pub fn get_i(&mut self) -> Option<i64> {
self.get_u().map(unzigzag)
}
pub fn get_bool(&mut self) -> Option<bool> {
match self.take(1)? {
[0] => Some(false),
[1] => Some(true),
_ => None,
}
}
pub fn get_f64(&mut self) -> Option<f64> {
Some(f64::from_le_bytes(self.take(F64_BYTES)?.try_into().ok()?))
}
pub fn get_f32(&mut self) -> Option<f32> {
Some(f32::from_le_bytes(self.take(F32_BYTES)?.try_into().ok()?))
}
fn count_of(&mut self, min: usize) -> Option<usize> {
let n = usize::try_from(self.get_u()?).ok()?;
(n <= (self.body.len() - self.i) / min.max(1)).then_some(n)
}
pub fn count(&mut self) -> Option<usize> {
self.count_of(1)
}
pub fn get_f64s(&mut self) -> Option<Vec<f64>> {
let (_, narrow, raw) = self.packed_floats(true)?;
Some(if narrow {
floats::widen(raw)
} else {
raw.as_chunks::<F64_BYTES>()
.0
.iter()
.map(|b| f64::from_le_bytes(*b))
.collect()
})
}
pub fn get_uints<T>(&mut self, of: impl Fn(u64) -> Option<T>) -> Option<Vec<T>> {
let (n, bits, raw) = self.packed_ints()?;
let mut out = Vec::with_capacity(n);
let mut ok = true;
lanes::unpack(raw, n, bits, |v| match of(v) {
Some(t) if ok => out.push(t),
_ => ok = false,
});
ok.then_some(out)
}
pub fn get_f32s(&mut self) -> Option<Vec<f32>> {
let (_, _, raw) = self.packed_floats(false)?;
Some(
raw.as_chunks::<F32_BYTES>()
.0
.iter()
.map(|b| f32::from_le_bytes(*b))
.collect(),
)
}
pub fn packed_ints(&mut self) -> Option<(usize, u32, &'b [u8])> {
let n = usize::try_from(self.get_u()?).ok()?;
let bits = u32::from(*self.take(1)?.first()?);
if !(1..=u64::BITS).contains(&bits)
|| n > (self.body.len() - self.i) * u8::BITS as usize / bits as usize
{
return None;
}
let bytes = self.take(lanes::packed_bytes(n, bits)?)?;
Some((n, bits, bytes))
}
pub fn packed_floats(&mut self, wide: bool) -> Option<(usize, bool, &'b [u8])> {
let n = self.count()?;
let narrow = if wide { self.get_bool()? } else { true };
let width = if narrow { F32_BYTES } else { F64_BYTES };
Some((n, narrow, self.take(n.checked_mul(width)?)?))
}
pub fn get_str(&mut self) -> Option<&'b str> {
let i = self.string_index()?;
self.strings.get(i)
}
pub fn get_shared_str(&mut self) -> Option<Arc<str>> {
let i = self.string_index()?;
if self.shared.len() <= i {
self.shared.resize(i + 1, None);
}
let s = self.strings.get(i)?;
Some(self.shared[i].get_or_insert_with(|| s.into()).clone())
}
fn string_index(&mut self) -> Option<usize> {
let i = usize::try_from(self.get_u()?).ok()?;
while self.strings.len() <= i {
let len = usize::try_from(read_varint(self.table, &mut self.table_at)?).ok()?;
let end = self
.table_at
.checked_add(len)
.filter(|&e| e <= self.table.len())?;
let s = std::str::from_utf8(&self.table[self.table_at..end]).ok()?;
self.table_at = end;
self.strings.push(s);
}
Some(i)
}
pub fn get_bytes(&mut self) -> Option<&'b [u8]> {
let len = self.count()?;
self.take(len)
}
pub fn get_tagged<T: Schema>(&mut self) -> Option<T> {
let bytes = self.get_bytes()?;
let mut d = Decoder::body(bytes);
if let Some(v) = T::decode(&mut d)
&& d.at_end()
{
return Some(v);
}
let arena = Bump::new();
let mut d = Decoder::body(bytes);
let v = d.value_ref(&arena).ok()?;
d.at_end().then_some(())?;
read_ref_value(&v).ok()
}
pub fn begin(&mut self) -> Option<usize> {
let len = self.count()?;
self.depth += 1;
(self.depth <= MAX_DEPTH).then_some(self.i + len)
}
pub fn list(&mut self) -> Option<(usize, usize)> {
let n = self.count()?;
let len = self.count()?;
Some((n, self.i + len))
}
pub fn skip_to(&mut self, end: usize) -> Option<()> {
(self.i <= end && end <= self.body.len()).then(|| self.i = end)
}
pub fn position(&self) -> usize {
self.i
}
pub fn fork(&self, at: usize) -> Unpacker<'b> {
Unpacker {
body: self.body,
i: at,
table: self.table,
table_at: 0,
strings: Strings::new(),
shared: Vec::new(),
depth: self.depth,
}
}
pub fn more(&self, end: usize) -> bool {
self.i < end
}
pub fn leave(&mut self, end: usize) -> Option<()> {
self.depth -= 1;
(self.i <= end).then(|| self.i = end)
}
}
fn read_varint_back(bytes: &[u8]) -> Option<(usize, usize)> {
let mut n = 0u64;
let mut shift = 0;
for (taken, b) in bytes.iter().rev().enumerate() {
if shift >= VARINT_MAX_SHIFT {
return None;
}
n |= (u64::from(*b) & VARINT_BITS) << shift;
if b & VARINT_MORE == 0 {
return Some((usize::try_from(n).ok()?, taken + 1));
}
shift += VARINT_SHIFT;
}
None
}