use std::collections::HashMap;
use std::hash::{BuildHasher, Hasher};
use crate::Table;
use crate::serialize::SerializeBytes;
pub struct VTableHasher(u64);
const FNV_OFFSET: u64 = 0xcbf29ce484222325;
const FNV_PRIME: u64 = 0x00000100000001b3;
impl Hasher for VTableHasher {
#[inline(always)]
fn finish(&self) -> u64 { self.0 }
#[inline(always)]
fn write(&mut self, bytes: &[u8]) {
let mut h = self.0;
for &b in bytes {
h ^= b as u64;
h = h.wrapping_mul(FNV_PRIME);
}
self.0 = h;
}
}
pub struct BuildVTableHasher;
impl BuildHasher for BuildVTableHasher {
type Hasher = VTableHasher;
fn build_hasher(&self) -> Self::Hasher { VTableHasher(FNV_OFFSET) }
}
pub struct DefaultBuffer {
pub buffer: Vec<u8>,
pub head: usize,
pub vtables: HashMap<Box<[u8]>, usize, BuildVTableHasher>,
}
impl Default for DefaultBuffer {
fn default() -> Self { Self::new(1024) }
}
impl Buffer for DefaultBuffer {
#[inline(always)]
fn new(initial_size: usize) -> Self {
let buffer = unsafe {
let mut v = Vec::<u8>::with_capacity(initial_size);
v.set_len(initial_size);
v
};
Self {
buffer,
head: initial_size,
vtables: HashMap::with_hasher(BuildVTableHasher),
}
}
fn buffer(&self) -> &[u8] { &self.buffer }
fn buffer_mut(&mut self) -> &mut [u8] { &mut self.buffer }
fn head(&self) -> usize { self.head }
fn head_mut(&mut self) -> &mut usize { &mut self.head }
fn grow(&mut self, new_cap: usize) {
debug_assert!(new_cap > self.buffer.len(),
"grow: new_cap ({new_cap}) must exceed current len ({})", self.buffer.len());
let old_cap = self.buffer.len();
let shift = new_cap - old_cap;
self.buffer.reserve(shift);
unsafe { self.buffer.set_len(new_cap); }
self.buffer.copy_within(0..old_cap, shift);
self.head += shift;
}
#[inline(always)]
fn clear_vtables(&mut self) { self.vtables.clear(); }
fn share_vtable(&mut self, vtable: &[u8], table_slot: usize) {
let vtable_slot = if let Some(&slot) = self.vtables.get(vtable) {
slot
} else {
let slot = vtable.write_bytes_to(self);
self.vtables.insert(Box::from(vtable), slot);
slot
};
let vtable_jump = (vtable_slot as i32) - (table_slot as i32);
let table_start_idx = self.len() - table_slot;
self.buffer_mut()[table_start_idx..table_start_idx + 4]
.copy_from_slice(&vtable_jump.to_le_bytes());
}
#[inline(always)]
fn load<T: Table>(bytes: &[u8]) -> Self {
let size = bytes.len();
let buffer = Self::new(size);
buffer
}
}
pub fn read_root(data: &[u8]) -> u32 {
let mut root_bytes = [0u8; 4];
root_bytes.copy_from_slice(&data[0..4]);
u32::from_le_bytes(root_bytes)
}
pub trait Buffer {
fn new(initial_capacity: usize) -> Self;
fn head(&self) -> usize;
fn head_mut(&mut self) -> &mut usize;
fn buffer(&self) -> &[u8];
fn buffer_mut(&mut self) -> &mut [u8];
fn share_vtable(&mut self, vtable: &[u8], table_slot: usize);
fn grow(&mut self, new_cap: usize);
fn load<T>(bytes: &[u8]) -> Self where T: Table;
fn clear_vtables(&mut self);
#[inline(always)]
fn reset(&mut self) {
let cap = self.len();
*self.head_mut() = cap;
self.clear_vtables();
}
#[inline(always)]
fn len(&self) -> usize { self.buffer().len() }
#[inline(always)]
fn ensure_capacity(&mut self, additional_size: usize) {
if self.head() <= additional_size {
let new_cap = (self.len() + additional_size).next_power_of_two();
self.grow(new_cap);
}
}
#[inline(always)]
fn slot(&self) -> usize { self.len() - self.head() }
#[inline(always)]
fn align(&mut self, alignment: usize) {
*self.head_mut() &= !(alignment - 1);
}
#[inline(always)]
fn bytes(&self) -> &[u8] { &self.buffer()[self.head()..] }
#[inline(always)]
fn finish(&mut self, slot: usize) -> &[u8] {
self.ensure_capacity(4);
let table_pos = self.len() - slot;
*self.head_mut() -= 4;
let head = self.head();
let relative_offset = (table_pos - head) as u32;
self.buffer_mut()[head..head + 4]
.copy_from_slice(&relative_offset.to_le_bytes());
self.bytes()
}
}
impl<B: Buffer> Buffer for &mut B {
#[inline(always)]
fn new(_: usize) -> Self {
panic!("Buffer::new on &mut B — allocate the owned B first")
}
#[inline(always)]
fn head(&self) -> usize { (**self).head() }
#[inline(always)]
fn head_mut(&mut self) -> &mut usize { (**self).head_mut() }
#[inline(always)]
fn buffer(&self) -> &[u8] { (**self).buffer() }
#[inline(always)]
fn buffer_mut(&mut self) -> &mut [u8] { (**self).buffer_mut() }
#[inline(always)]
fn grow(&mut self, n: usize) { (**self).grow(n) }
#[inline(always)]
fn clear_vtables(&mut self) { (**self).clear_vtables() }
#[inline(always)]
fn share_vtable(&mut self, vt: &[u8], slot: usize) {
(**self).share_vtable(vt, slot)
}
#[inline(always)]
fn load<T: crate::Table>(_: &[u8]) -> Self {
panic!("Buffer::load on &mut B — not supported")
}
}