preserves/implementations/rust/src/value/packed/writer.rs

315 lines
12 KiB
Rust

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: std::io::Write>(w: &mut PackedWriter<W>, op: Op, arg: u8) -> Result<()> {
w.0.write_all(&[(u8::from(op) << 4) | (arg & 15)])
}
pub fn write_header<W: std::io::Write>(w: &mut PackedWriter<W>, 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: std::io::Write>(w: &mut PackedWriter<W>, 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<u8>> {
pub fn encode(v: &IOValue) -> std::io::Result<Vec<u8>> {
let mut buf: Vec<u8> = 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<Self::Annotation> {
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<Self::Pointer> {
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<Option<Self::StreamedAtom>> {
write_op(self, Op::Misc(2), Op::Atom(AtomMinor::String).into())?;
Ok(Some(()))
}
fn stream_bytes(&mut self) -> Result<Option<Self::StreamedAtom>> {
write_op(self, Op::Misc(2), Op::Atom(AtomMinor::ByteString).into())?;
Ok(Some(()))
}
fn stream_symbol(&mut self) -> Result<Option<Self::StreamedAtom>> {
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<Self::Compound> {
write_header(self, Op::Compound(CompoundMinor::Record), field_count + 1)?;
Ok(false)
}
fn start_sequence(&mut self, item_count: usize) -> Result<Self::Compound> {
write_header(self, Op::Compound(CompoundMinor::Sequence), item_count)?;
Ok(false)
}
fn start_set(&mut self, item_count: usize) -> Result<Self::Compound> {
write_header(self, Op::Compound(CompoundMinor::Set), item_count)?;
Ok(false)
}
fn stream_record(&mut self) -> Result<Option<Self::Compound>> {
write_op(self, Op::Misc(2), Op::Compound(CompoundMinor::Record).into())?;
Ok(Some(true))
}
fn stream_sequence(&mut self) -> Result<Option<Self::Compound>> {
write_op(self, Op::Misc(2), Op::Compound(CompoundMinor::Sequence).into())?;
Ok(Some(true))
}
fn stream_set(&mut self) -> Result<Option<Self::Compound>> {
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<Self::Dictionary> {
write_header(self, Op::Compound(CompoundMinor::Dictionary), entry_count << 1)?;
Ok(false)
}
fn stream_dictionary(&mut self) -> Result<Option<Self::Dictionary>> {
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<Self::KeyPointer> {
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)
}
}