use super::shape_cache::ShapeCache;
use crate::binary::{
INLINE_INT_MAX, INLINE_INT_MIN, MAGIC, NEW_STRING, STR_INDEX_COUNT, VERSION, tag, varint,
zigzag,
};
use crate::wire::binary::layout::{narrow, narrows};
use crate::wire::binary::table::interner::Interner;
use crate::wire::binary::table::shape_table::ShapeTable;
pub(crate) const START_BYTES: usize = 256;
#[derive(Debug)]
pub struct Writer {
pub(in crate::wire::binary) out: Vec<u8>,
pub(in crate::wire::binary) strings: Interner,
pub(in crate::wire::binary) shapes: ShapeTable,
pub(in crate::wire::binary) cache: ShapeCache,
}
impl Default for Writer {
fn default() -> Self {
Self::new()
}
}
impl Writer {
#[must_use]
pub fn new() -> Self {
let mut out = Vec::with_capacity(START_BYTES);
out.extend_from_slice(MAGIC);
out.push(VERSION);
Self::over(out)
}
fn over(out: Vec<u8>) -> Self {
Writer {
out,
strings: Interner::new(),
shapes: ShapeTable::default(),
cache: ShapeCache::default(),
}
}
pub(crate) fn appending(mut out: Vec<u8>) -> Self {
out.extend_from_slice(MAGIC);
out.push(VERSION);
Self::over(out)
}
pub(crate) fn restart(&mut self, prefix: usize) {
self.out.clear();
self.out.resize(prefix, 0);
self.out.extend_from_slice(MAGIC);
self.out.push(VERSION);
self.strings.clear();
self.shapes.clear();
self.cache.clear();
}
pub(crate) fn buffer_mut(&mut self) -> &mut Vec<u8> {
&mut self.out
}
pub fn null(&mut self) -> &mut Self {
self.out.push(tag::NULL);
self
}
pub fn bool(&mut self, b: bool) -> &mut Self {
self.out.push(if b { tag::TRUE } else { tag::FALSE });
self
}
#[inline]
pub fn int(&mut self, n: i64) -> &mut Self {
let inline = u8::try_from(n.wrapping_sub(INLINE_INT_MIN))
.ok()
.filter(|&at| i64::from(at) <= INLINE_INT_MAX - INLINE_INT_MIN);
if let Some(at) = inline {
self.out.push(tag::INT_INLINE + at);
return self;
}
self.out.push(tag::INT);
varint(&mut self.out, zigzag(n));
self
}
pub fn float(&mut self, f: f64) -> &mut Self {
if narrows(f) {
return self.float32(narrow(f));
}
self.out.push(tag::FLOAT);
self.out.extend_from_slice(&f.to_le_bytes());
self
}
pub fn float32(&mut self, f: f32) -> &mut Self {
self.out.push(tag::FLOAT32);
self.out.extend_from_slice(&f.to_le_bytes());
self
}
pub fn str(&mut self, s: &str) -> &mut Self {
let found = self.strings.lookup(&self.out, s);
if let Ok(i) = found
&& let Ok(at) = u8::try_from(i)
&& at < STR_INDEX_COUNT
{
self.out.push(tag::STR_INDEX + at);
return self;
}
self.out.push(tag::STR);
self.put_string(s, found);
self
}
pub fn bytes(&mut self, b: &[u8]) -> &mut Self {
self.out.push(tag::BYTES);
varint(&mut self.out, b.len() as u64);
self.out.extend_from_slice(b);
self
}
pub fn list(&mut self, len: usize) -> &mut Self {
self.out.push(tag::LIST);
varint(&mut self.out, len as u64);
self
}
pub(crate) fn stream_body(&mut self, len: usize, items: &[u8]) -> &mut Self {
let mut count = Vec::new();
varint(&mut count, len as u64);
self.out.push(tag::STREAM);
let body = u32::try_from(count.len() + items.len()).unwrap_or(u32::MAX);
self.out.extend_from_slice(&body.to_le_bytes());
self.out.extend_from_slice(&count);
self.out.extend_from_slice(items);
self
}
pub(crate) fn body() -> Self {
Self::over(Vec::with_capacity(START_BYTES))
}
pub fn map(&mut self, len: usize) -> &mut Self {
self.out.push(tag::MAP);
varint(&mut self.out, len as u64);
self
}
pub fn key(&mut self, k: &str) -> &mut Self {
self.string(k);
self
}
#[must_use]
pub fn finish(self) -> Vec<u8> {
self.out
}
pub(in crate::wire::binary) fn string(&mut self, s: &str) -> usize {
let found = self.strings.find(&self.out, s);
self.put_string(s, found)
}
#[inline]
pub(in crate::wire::binary) fn put_string(
&mut self,
s: &str,
found: Result<usize, Option<u32>>,
) -> usize {
match found {
Ok(i) => {
varint(&mut self.out, (i as u64) << 1);
i
}
Err(hash) => {
varint(&mut self.out, ((s.len() as u64) << 1) | NEW_STRING);
let at = self.out.len();
self.out.extend_from_slice(s.as_bytes());
self.strings.add(&self.out, s, at, hash)
}
}
}
}