preserves/implementations/rust/src/value/encoder.rs

129 lines
4.6 KiB
Rust

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<N, D> = Map<Value<N, D>, usize>;
pub struct Encoder<'a, 'b, W: Write, N: NestedValue<D>, D: Domain> {
pub write: &'a mut W,
pub placeholders: Option<&'b EncodePlaceholderMap<N, D>>,
}
impl<'a, 'b, W: Write, N: NestedValue<D>, D: Domain> Encoder<'a, 'b, W, N, D> {
pub fn new(write: &'a mut W, placeholders: Option<&'b EncodePlaceholderMap<N, D>>) -> 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<N, D>) -> 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),
}
}
}
}