use std::io::Write; use crate::value::value::{Value, NestedValue, Float, Double, Map, Domain}; use num::bigint::BigInt; use num::cast::ToPrimitive; use crate::value::constants::{Op, AtomMinor, CompoundMinor}; pub type Error = std::io::Error; pub type Result = std::result::Result<(), Error>; pub type EncodePlaceholderMap = Map, usize>; pub struct Encoder<'a, 'b, W: Write, N: NestedValue, D: Domain> { pub write: &'a mut W, pub placeholders: Option<&'b EncodePlaceholderMap>, } impl<'a, 'b, W: Write, N: NestedValue, D: Domain> Encoder<'a, 'b, W, N, D> { pub fn new(write: &'a mut W, placeholders: Option<&'b EncodePlaceholderMap>) -> Self { Encoder{ write, placeholders } } pub fn _write(&mut self, v: u8) -> Result { self.write_all(&[v]) } pub fn write_all(&mut self, vs: &[u8]) -> Result { self.write.write_all(vs) } pub fn varint(&mut self, v: usize) -> Result { if v < 128 { self._write(v as u8) } else { self._write(((v & 0x7f) + 128) as u8)?; self.varint(v >> 7) } } pub fn write_op(&mut self, op: Op, arg: u8) -> Result { self._write((u8::from(op) << 4) | (arg & 15)) } pub fn write_header(&mut self, op: Op, wirelength: usize) -> Result { if wirelength < 15 { self.write_op(op, wirelength as u8) } else { self.write_op(op, 15)?; self.varint(wirelength) } } pub fn write_int(&mut self, v: &BigInt) -> Result { match v.to_i8() { Some(n) if n >= 0 && n <= 12 => self.write_op(Op::Misc(3), n as u8), Some(n) if n >= -3 && n < 0 => self.write_op(Op::Misc(3), (n + 16) as u8), _ => self.write_atom(AtomMinor::SignedInteger, &v.to_signed_bytes_be()), } } pub fn write_stream_header(&mut self, op: Op) -> Result { self.write_op(Op::Misc(2), u8::from(op)) } pub fn write_stream_footer(&mut self) -> Result { self.write_op(Op::Misc(0), 4) } pub fn write_atom(&mut self, minor: AtomMinor, bs: &[u8]) -> Result { self.write_header(Op::Atom(minor), bs.len())?; self.write_all(bs) } pub fn write_noop(&mut self) -> Result { self.write_op(Op::Reserved(3), 15) } pub fn write(&mut self, v: &N) -> Result { for ann in v.annotations() { self.write_header(Op::Misc(0), 5)?; self.write(ann)?; } self.write_value(v.value()) } pub fn write_value(&mut self, v: &Value) -> Result { match self.placeholders.and_then(|m| m.get(v)) { Some(&n) => self.write_header(Op::Misc(1), n), None => match v { Value::Boolean(false) => self.write_op(Op::Misc(0), 0), Value::Boolean(true) => self.write_op(Op::Misc(0), 1), Value::Float(Float(f)) => { self.write_op(Op::Misc(0), 2)?; self.write_all(&u32::to_be_bytes(f32::to_bits(*f))) } Value::Double(Double(d)) => { self.write_op(Op::Misc(0), 3)?; self.write_all(&u64::to_be_bytes(f64::to_bits(*d))) } Value::SignedInteger(ref b) => self.write_int(b), Value::String(ref s) => self.write_atom(AtomMinor::String, s.as_bytes()), Value::ByteString(ref bs) => self.write_atom(AtomMinor::ByteString, bs), Value::Symbol(ref s) => self.write_atom(AtomMinor::Symbol, s.as_bytes()), Value::Record((ref l, ref fs)) => { self.write_header(Op::Compound(CompoundMinor::Record), fs.len() + 1)?; self.write(N::boxunwrap(l))?; for f in fs { self.write(f)?; } Ok(()) } Value::Sequence(ref vs) => { self.write_header(Op::Compound(CompoundMinor::Sequence), vs.len())?; for v in vs { self.write(v)?; } Ok(()) } Value::Set(ref vs) => { self.write_header(Op::Compound(CompoundMinor::Set), vs.len())?; for v in vs { self.write(v)?; } Ok(()) } Value::Dictionary(ref vs) => { self.write_header(Op::Compound(CompoundMinor::Dictionary), vs.len() << 1)?; for (k, v) in vs { self.write(k)?; self.write(v)?; } Ok(()) } Value::Domain(ref d) => d.encode(self), } } } }