binprot 0.1.7

Rust implementation of the bin_prot protocol.
Documentation
use crate::Shape;
use std::collections::{hash_map::Entry, HashMap};
use std::io::{Read, Write};

pub type ShapeContext = HashMap<std::any::TypeId, bool>;

pub trait BinProtShape: 'static {
    fn binprot_shape_impl(_: &mut ShapeContext) -> Shape;

    fn binprot_shape_loop(typeids: &mut ShapeContext) -> Shape {
        let typeid = std::any::TypeId::of::<Self>();
        match typeids.entry(typeid) {
            Entry::Occupied(mut e) => {
                // TODO: Adjust the parameters.
                e.insert(true);
                Shape::RecApp(0, vec![])
            }
            Entry::Vacant(e) => {
                e.insert(false);
                let shape = Self::binprot_shape_impl(typeids);
                match typeids.remove(&typeid) {
                    None | Some(false) => shape,
                    Some(true) => Shape::Application(Box::new(shape), vec![]),
                }
            }
        }
    }

    fn binprot_shape() -> Shape {
        let mut typeids = HashMap::new();
        Self::binprot_shape_loop(&mut typeids)
    }
}

pub trait BinProtSize {
    fn binprot_size(&self) -> usize;
}

pub trait BinProtWrite {
    fn binprot_write<W: Write>(&self, w: &mut W) -> std::io::Result<()>;
}

pub trait BinProtRead {
    fn binprot_read<R: Read + ?Sized>(r: &mut R) -> Result<Self, crate::error::Error>
    where
        Self: Sized;
}

struct SizeWrite(usize);

impl Write for SizeWrite {
    fn write(&mut self, data: &[u8]) -> std::result::Result<usize, std::io::Error> {
        let len = data.len();
        self.0 += len;
        Ok(len)
    }
    fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
        Ok(())
    }
}

impl SizeWrite {
    fn new() -> Self {
        SizeWrite(0)
    }
}

impl<T: BinProtWrite> BinProtSize for T {
    fn binprot_size(&self) -> usize {
        let mut w = SizeWrite::new();
        self.binprot_write(&mut w).unwrap();
        w.0
    }
}