use num_bigint::BigInt; use num_traits::cast::ToPrimitive; use std::convert::TryInto; use std::io; use std::io::Write; use super::constants::Tag; use crate::{boundary as B, ValueImpl, DomainEncode, Writer, DefaultDomainCodec}; struct Buffers { base: W, stack: Vec>>, } impl io::Write for Buffers { fn write(&mut self, buf: &[u8]) -> io::Result { if self.stack.is_empty() { self.base.write(buf) } else { self.stack .last_mut().unwrap() .last_mut().expect("Internal error: PackedWriter buffer sequence underflow") .write(buf) } } fn flush(&mut self) -> io::Result<()> { if self.stack.is_empty() { self.base.flush() } else { Ok(()) } } } pub struct PackedWriter(Buffers); impl PackedWriter<&mut Vec> { #[inline(always)] pub fn encode_domain<'de, V: ValueImpl<'de>, Enc: DomainEncode<'de, V::Embedded>>( enc: &mut Enc, v: &V, ) -> io::Result> { let mut buf: Vec = Vec::new(); v.write(&mut PackedWriter::new(&mut buf), enc)?; Ok(buf) } #[inline(always)] pub fn encode<'de, V: ValueImpl<'de>>(v: &V) -> io::Result> { Self::encode_domain(&mut DefaultDomainCodec, v) } } pub fn varint(w: &mut W, mut v: u64) -> io::Result { let mut byte_count = 0; loop { byte_count += 1; if v < 128 { w.write_all(&[v as u8])?; return Ok(byte_count); } else { w.write_all(&[((v & 0x7f) + 128) as u8])?; v >>= 7; } } } impl PackedWriter { #[inline(always)] pub fn new(write: W) -> Self { PackedWriter(Buffers { base: write, stack: vec![], }) } #[inline(always)] pub fn write_byte(&mut self, b: u8) -> io::Result<()> { self.0.write_all(&[b]) } #[inline(always)] pub fn write_medium_integer(&mut self, bs: &[u8]) -> io::Result<()> { let count: u8 = bs.len().try_into().unwrap(); if !(1..=16).contains(&count) { panic!("Invalid medium_integer count: {}", count) } self.write_byte(Tag::MediumInteger(count).into())?; self.0.write_all(bs) } #[inline(always)] pub fn write_atom(&mut self, tag: Tag, bs: &[u8]) -> io::Result<()> { self.write_byte(tag.into())?; varint(&mut self.0, bs.len().try_into().unwrap())?; self.0.write_all(bs) } fn push(&mut self) -> io::Result<()> { self.0.stack.push(vec![vec![]]); Ok(()) } fn shift(&mut self) { match self.0.stack.last_mut() { Some(bss) => bss.push(vec![]), None => panic!("Internal error: Preserves PackedWriter stack underflow"), } } fn pop(&mut self, sorted: bool) -> io::Result<()> { match self.0.stack.pop() { Some(mut bss) => { if sorted { bss.sort(); } for bs in bss { self.0.write_all(&bs)? } Ok(()) } None => panic!("Internal error: Preserves PackedWriter stack underflow"), } } #[inline(always)] fn write_tag(&mut self, tag: Tag) -> io::Result<()> { self.write_byte(tag.into()) } } macro_rules! fits_in_bytes { ($v:ident, $limit:literal) => ({ let bits = $limit * 8 - 1; $v >= -(2 << bits) && $v < (2 << bits) }) } impl Writer for PackedWriter { #[inline(always)] fn boundary(&mut self, b: &B::Type) -> io::Result<()> { match b.closing { Some(B::Item::DictionaryValue) | Some(B::Item::SetValue) => self.shift(), _ => () } match b.opening { Some(B::Item::Annotation) => self.write_tag(Tag::Annotation)?, _ => () } Ok(()) } #[inline(always)] fn start_annotations(&mut self) -> io::Result<()> { Ok(()) } #[inline(always)] fn end_annotations(&mut self) -> io::Result<()> { Ok(()) } #[inline(always)] fn write_bool(&mut self, v: bool) -> io::Result<()> { self.write_tag(if v { Tag::True } else { Tag::False }) } #[inline(always)] fn write_f32(&mut self, v: f32) -> io::Result<()> { self.write_tag(Tag::Float)?; self.0.write_all(&u32::to_be_bytes(f32::to_bits(v))) } #[inline(always)] fn write_f64(&mut self, v: f64) -> io::Result<()> { self.write_tag(Tag::Double)?; self.0.write_all(&u64::to_be_bytes(f64::to_bits(v))) } #[inline(always)] fn write_i8(&mut self, v: i8) -> io::Result<()> { if v >= -3 && v <= 12 { return self.write_tag(Tag::SmallInteger(v)) } self.write_medium_integer(&[v as u8]) } #[inline(always)] fn write_u8(&mut self, v: u8) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i8(w) } self.write_medium_integer(&[0, v]) } #[inline(always)] fn write_i16(&mut self, v: i16) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i8(w) } self.write_medium_integer(&[(v >> 8) as u8, (v & 255) as u8]) } #[inline(always)] fn write_u16(&mut self, v: u16) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i16(w) } self.write_medium_integer(&[0, (v >> 8) as u8, (v & 255) as u8]) } #[inline(always)] fn write_i32(&mut self, v: i32) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i16(w) } if fits_in_bytes!(v, 3) { return self.write_medium_integer(&[(v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]); } self.write_medium_integer(&[(v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]) } #[inline(always)] fn write_u32(&mut self, v: u32) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i32(w) } self.write_medium_integer(&[0, (v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]) } #[inline(always)] fn write_i64(&mut self, v: i64) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i32(w) } if fits_in_bytes!(v, 5) { return self.write_medium_integer(&[(v >> 32) as u8, (v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]); } if fits_in_bytes!(v, 6) { return self.write_medium_integer(&[(v >> 40) as u8, (v >> 32) as u8, (v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]); } if fits_in_bytes!(v, 7) { return self.write_medium_integer(&[(v >> 48) as u8, (v >> 40) as u8, (v >> 32) as u8, (v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]); } self.write_medium_integer(&[(v >> 56) as u8, (v >> 48) as u8, (v >> 40) as u8, (v >> 32) as u8, (v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]) } #[inline(always)] fn write_u64(&mut self, v: u64) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i64(w) } self.write_medium_integer(&[0, (v >> 56) as u8, (v >> 48) as u8, (v >> 40) as u8, (v >> 32) as u8, (v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]) } #[inline(always)] fn write_i128(&mut self, v: i128) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i64(w) } let bs: [u8; 16] = v.to_be_bytes(); if fits_in_bytes!(v, 9) { return self.write_medium_integer(&bs[7..]); } if fits_in_bytes!(v, 10) { return self.write_medium_integer(&bs[6..]); } if fits_in_bytes!(v, 11) { return self.write_medium_integer(&bs[5..]); } if fits_in_bytes!(v, 12) { return self.write_medium_integer(&bs[4..]); } if fits_in_bytes!(v, 13) { return self.write_medium_integer(&bs[3..]); } if fits_in_bytes!(v, 14) { return self.write_medium_integer(&bs[2..]); } if fits_in_bytes!(v, 15) { return self.write_medium_integer(&bs[1..]); } self.write_medium_integer(&bs) } #[inline(always)] fn write_u128(&mut self, v: u128) -> io::Result<()> { if let Ok(w) = v.try_into() { return self.write_i128(w) } let bs: [u8; 16] = v.to_be_bytes(); self.write_tag(Tag::SignedInteger)?; varint(&mut self.0, 17)?; self.write_byte(0)?; self.0.write_all(&bs) } #[inline(always)] fn write_int(&mut self, v: &BigInt) -> io::Result<()> { match v.to_i8() { Some(n) => self.write_i8(n), None => { match v.to_i128() { Some(n) => self.write_i128(n), None => self.write_atom(Tag::SignedInteger, &v.to_signed_bytes_be()), } } } } #[inline(always)] fn write_string(&mut self, v: &str) -> io::Result<()> { self.write_atom(Tag::String, v.as_bytes()) } #[inline(always)] fn write_bytes(&mut self, v: &[u8]) -> io::Result<()> { self.write_atom(Tag::ByteString, v) } #[inline(always)] fn write_symbol(&mut self, v: &str) -> io::Result<()> { self.write_atom(Tag::Symbol, v.as_bytes()) } #[inline(always)] fn start_record(&mut self) -> io::Result<()> { self.write_tag(Tag::Record) } #[inline(always)] fn end_record(&mut self) -> io::Result<()> { self.write_tag(Tag::End) } #[inline(always)] fn start_sequence(&mut self) -> io::Result<()> { self.write_tag(Tag::Sequence) } #[inline(always)] fn end_sequence(&mut self) -> io::Result<()> { self.write_tag(Tag::End) } #[inline(always)] fn start_set(&mut self) -> io::Result<()> { self.write_tag(Tag::Set)?; self.push() } #[inline(always)] fn end_set(&mut self) -> io::Result<()> { self.pop(true)?; self.write_tag(Tag::End) } #[inline(always)] fn start_dictionary(&mut self) -> io::Result<()> { self.write_tag(Tag::Dictionary)?; self.push() } #[inline(always)] fn end_dictionary(&mut self) -> io::Result<()> { self.pop(true)?; self.write_tag(Tag::End) } #[inline(always)] fn start_embedded(&mut self) -> io::Result<()> { self.write_tag(Tag::Embedded) } #[inline(always)] fn end_embedded(&mut self) -> io::Result<()> { Ok(()) } #[inline(always)] fn flush(&mut self) -> io::Result<()> { self.0.flush() } fn specialized(&mut self) -> Option<(&str, &mut dyn io::Write)> { Some(("packed", &mut self.0)) } }