395 lines
12 KiB
Rust
395 lines
12 KiB
Rust
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<W: io::Write> {
|
|
base: W,
|
|
stack: Vec<Vec<Vec<u8>>>,
|
|
}
|
|
|
|
impl<W: io::Write> io::Write for Buffers<W> {
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
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<W: io::Write>(Buffers<W>);
|
|
|
|
impl PackedWriter<&mut Vec<u8>> {
|
|
#[inline(always)]
|
|
pub fn encode_domain<'de, V: ValueImpl<'de>, Enc: DomainEncode<'de, V::Embedded>>(
|
|
enc: &mut Enc,
|
|
v: &V,
|
|
) -> io::Result<Vec<u8>> {
|
|
let mut buf: Vec<u8> = 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<Vec<u8>> {
|
|
Self::encode_domain(&mut DefaultDomainCodec, v)
|
|
}
|
|
}
|
|
|
|
pub fn varint<W: io::Write>(w: &mut W, mut v: u64) -> io::Result<usize> {
|
|
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<W: io::Write> PackedWriter<W> {
|
|
#[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<W: io::Write> Writer for PackedWriter<W>
|
|
{
|
|
#[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))
|
|
}
|
|
}
|