use num; use num::bigint::BigInt; use num::cast::ToPrimitive; use std::convert::TryInto; use super::constants::{Op, AtomMinor, CompoundMinor}; use super::super::IOValue; use super::super::writer::{Writer, Result, varint}; pub struct PackedWriter<'w, W: std::io::Write>(pub &'w mut W); pub fn write_op(w: &mut PackedWriter, op: Op, arg: u8) -> Result<()> { w.0.write_all(&[(u8::from(op) << 4) | (arg & 15)]) } pub fn write_header(w: &mut PackedWriter, op: Op, wirelength: usize) -> Result<()> { if wirelength < 15 { write_op(w, op, wirelength as u8) } else { write_op(w, op, 15)?; varint(w.0, wirelength as u64)?; Ok(()) } } pub fn write_atom(w: &mut PackedWriter, minor: AtomMinor, bs: &[u8]) -> Result<()> { write_header(w, Op::Atom(minor), bs.len())?; w.0.write_all(bs) } macro_rules! fits_in_bytes { ($v:ident, $limit:literal) => ({ let bits = $limit * 8 - 1; $v >= -(2 << bits) && $v < (2 << bits) }) } impl<'w, W: std::io::Write> PackedWriter<'w, W> { pub fn write_noop(&mut self) -> Result<()> { write_op(self, Op::Reserved(3), 15) } } impl<'w> PackedWriter<'w, &'w mut Vec> { pub fn encode(v: &IOValue) -> std::io::Result> { let mut buf: Vec = Vec::new(); PackedWriter(&mut buf).write(v)?; { use pretty_hex::*; println!("Packed:\n{:?}\n", &buf.hex_dump()); super::super::indexed::IndexedWriter::encode(v)?; } Ok(buf) } } impl<'w, W: std::io::Write> Writer for PackedWriter<'w, W> { type Pointer = (); type Annotation = (); type Compound = bool; type Dictionary = bool; type StreamedAtom = (); type KeyPointer = (); fn start_annotation(&mut self) -> Result { Ok(()) } fn extend_annotation(&mut self, _a: &mut Self::Annotation, annotation: &IOValue) -> Result<()> { write_header(self, Op::Misc(0), 5)?; self.write(annotation) } fn end_annotation(&mut self, _a: Self::Annotation, _value_p: Self::Pointer) -> Result { Ok(()) } fn align(&mut self, _natural_chunksize: u64) -> Result<()> { Ok(()) } fn write_bool(&mut self, v: bool) -> Result<()> { write_op(self, Op::Misc(0), if v { 1 } else { 0 }) } fn write_f32(&mut self, v: f32) -> Result<()> { write_op(self, Op::Misc(0), 2)?; self.0.write_all(&u32::to_be_bytes(f32::to_bits(v))) } fn write_f64(&mut self, v: f64) -> Result<()> { write_op(self, Op::Misc(0), 3)?; self.0.write_all(&u64::to_be_bytes(f64::to_bits(v))) } fn write_i8(&mut self, v: i8) -> Result<()> { if v >= 0 && v <= 12 { return write_op(self, Op::Misc(3), v as u8) } if v >= -3 && v < 0 { return write_op(self, Op::Misc(3), (v + 16) as u8) } write_atom(self, AtomMinor::SignedInteger, &[v as u8]) } fn write_u8(&mut self, v: u8) -> Result<()> { if let Ok(w) = v.try_into() { return self.write_i8(w) } write_atom(self, AtomMinor::SignedInteger, &[0, v]) } fn write_i16(&mut self, v: i16) -> Result<()> { if let Ok(w) = v.try_into() { return self.write_i8(w) } write_atom(self, AtomMinor::SignedInteger, &[(v >> 8) as u8, (v & 255) as u8]) } fn write_u16(&mut self, v: u16) -> Result<()> { if let Ok(w) = v.try_into() { return self.write_i16(w) } write_atom(self, AtomMinor::SignedInteger, &[0, (v >> 8) as u8, (v & 255) as u8]) } fn write_i32(&mut self, v: i32) -> Result<()> { if let Ok(w) = v.try_into() { return self.write_i16(w) } if fits_in_bytes!(v, 3) { return write_atom(self, AtomMinor::SignedInteger, &[(v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]); } return write_atom(self, AtomMinor::SignedInteger, &[(v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]); } fn write_u32(&mut self, v: u32) -> Result<()> { if let Ok(w) = v.try_into() { return self.write_i32(w) } return write_atom(self, AtomMinor::SignedInteger, &[0, (v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, (v & 255) as u8]); } fn write_i64(&mut self, v: i64) -> Result<()> { if let Ok(w) = v.try_into() { return self.write_i32(w) } if fits_in_bytes!(v, 5) { return write_atom(self, AtomMinor::SignedInteger, &[(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 write_atom(self, AtomMinor::SignedInteger, &[(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 write_atom(self, AtomMinor::SignedInteger, &[(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]); } return write_atom(self, AtomMinor::SignedInteger, &[(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]); } fn write_u64(&mut self, v: u64) -> Result<()> { if let Ok(w) = v.try_into() { return self.write_i64(w) } return write_atom(self, AtomMinor::SignedInteger, &[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]); } fn write_i128(&mut self, v: i128) -> 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 write_atom(self, AtomMinor::SignedInteger, &bs[7..]); } if fits_in_bytes!(v, 10) { return write_atom(self, AtomMinor::SignedInteger, &bs[6..]); } if fits_in_bytes!(v, 11) { return write_atom(self, AtomMinor::SignedInteger, &bs[5..]); } if fits_in_bytes!(v, 12) { return write_atom(self, AtomMinor::SignedInteger, &bs[4..]); } if fits_in_bytes!(v, 13) { return write_atom(self, AtomMinor::SignedInteger, &bs[3..]); } if fits_in_bytes!(v, 14) { return write_atom(self, AtomMinor::SignedInteger, &bs[2..]); } if fits_in_bytes!(v, 15) { return write_atom(self, AtomMinor::SignedInteger, &bs[1..]); } return write_atom(self, AtomMinor::SignedInteger, &bs); } fn write_u128(&mut self, v: u128) -> Result<()> { if let Ok(w) = v.try_into() { return self.write_i128(w) } let bs: [u8; 16] = v.to_be_bytes(); write_header(self, Op::Atom(AtomMinor::SignedInteger), bs.len() + 1)?; self.0.write_all(&[0])?; self.0.write_all(&bs) } fn write_int(&mut self, v: &BigInt) -> Result<()> { match v.to_i8() { Some(n) => self.write_i8(n), None => write_atom(self, AtomMinor::SignedInteger, &v.to_signed_bytes_be()), } } fn write_string(&mut self, v: &str) -> Result<()> { write_atom(self, AtomMinor::String, v.as_bytes()) } fn write_bytes(&mut self, v: &[u8]) -> Result<()> { write_atom(self, AtomMinor::ByteString, v) } fn write_symbol(&mut self, v: &str) -> Result<()> { write_atom(self, AtomMinor::Symbol, v.as_bytes()) } fn stream_string(&mut self) -> Result> { write_op(self, Op::Misc(2), Op::Atom(AtomMinor::String).into())?; Ok(Some(())) } fn stream_bytes(&mut self) -> Result> { write_op(self, Op::Misc(2), Op::Atom(AtomMinor::ByteString).into())?; Ok(Some(())) } fn stream_symbol(&mut self) -> Result> { write_op(self, Op::Misc(2), Op::Atom(AtomMinor::Symbol).into())?; Ok(Some(())) } fn extend_atom(&mut self, _s: &mut Self::StreamedAtom, bs: &[u8]) -> Result<()> { self.write_bytes(bs) } fn end_atom(&mut self, _s: Self::StreamedAtom) -> Result<()> { write_op(self, Op::Misc(0), 4) } fn start_record(&mut self, field_count: usize) -> Result { write_header(self, Op::Compound(CompoundMinor::Record), field_count + 1)?; Ok(false) } fn start_sequence(&mut self, item_count: usize) -> Result { write_header(self, Op::Compound(CompoundMinor::Sequence), item_count)?; Ok(false) } fn start_set(&mut self, item_count: usize) -> Result { write_header(self, Op::Compound(CompoundMinor::Set), item_count)?; Ok(false) } fn stream_record(&mut self) -> Result> { write_op(self, Op::Misc(2), Op::Compound(CompoundMinor::Record).into())?; Ok(Some(true)) } fn stream_sequence(&mut self) -> Result> { write_op(self, Op::Misc(2), Op::Compound(CompoundMinor::Sequence).into())?; Ok(Some(true)) } fn stream_set(&mut self) -> Result> { write_op(self, Op::Misc(2), Op::Compound(CompoundMinor::Set).into())?; Ok(Some(true)) } fn extend_compound(&mut self, _s: &mut Self::Compound, _value_p: Self::Pointer) -> Result<()> { Ok(()) } fn end_compound(&mut self, s: Self::Compound) -> Result<()> { if s { write_op(self, Op::Misc(0), 4) } else { Ok(()) } } fn start_dictionary(&mut self, entry_count: usize) -> Result { write_header(self, Op::Compound(CompoundMinor::Dictionary), entry_count << 1)?; Ok(false) } fn stream_dictionary(&mut self) -> Result> { write_op(self, Op::Misc(2), Op::Compound(CompoundMinor::Dictionary).into())?; Ok(Some(true)) } fn extend_dictionary_key(&mut self, _s: &mut Self::Dictionary, _key_p: Self::Pointer) -> Result { Ok(()) } fn extend_dictionary_value(&mut self, _s: &mut Self::Dictionary, _key_p: Self::KeyPointer, _value_p: Self::Pointer) -> Result<()> { Ok(()) } fn end_dictionary(&mut self, s: Self::Dictionary) -> Result<()> { self.end_compound(s) } }