pigeon 0.1.0

Utilities for efficient packing and unpacking of big-endian binary data
Documentation
use std::convert::TryInto;

use super::{Dump, FrameReader, FrameTarget, FrameWriter, Grab};

macro_rules! impl_for_numeric {
    ($size:literal, $t:ty) => {
        impl Dump for $t {
            fn dump_to<T: FrameTarget>(&self, writer: &mut FrameWriter<T>) {
                let bytes = self.to_be_bytes();
                writer.write_bytes(&bytes[..]);
            }
        }

        impl<'a> Grab<'a> for $t {
            fn grab_from(reader: &mut FrameReader<'a>) -> Option<Self> {
                reader
                    .read_bytes($size)
                    .map(|bytes| Self::from_be_bytes(bytes.try_into().unwrap()))
            }
        }
    };
}

macro_rules! impl_for_numeric_multi {
    ($(($size:literal, $t:ty),)*) => {
        $( impl_for_numeric!($size, $t); )*
    }
}

macro_rules! impl_for_tuple {
    ($($v:ident $t:ident),*) => {
        impl < $($t : Dump),* > Dump for ($($t),*) {
            fn dump_to<T: FrameTarget>(&self, writer: &mut FrameWriter<T>) {
                let ($($v),*) = self;
                $(
                    writer.write($v);
                )*
            }
        }

        impl < 'a, $($t : Grab<'a> ),*> Grab<'a> for ($($t),*) {
            fn grab_from(reader: &mut FrameReader<'a>) -> Option<Self> {
                $(
                    let $v = reader.read()?;
                )*
                Some(($(
                    $v
                ),*))
            }
        }
    }
}

macro_rules! impl_for_tuple_multi {
    ($($args:tt,)*) => {
        $( impl_for_tuple! $args; )*
    }
}

impl<'a, A: Dump> Dump for &'a A {
    fn dump_to<T: FrameTarget>(&self, writer: &mut FrameWriter<T>) {
        (**self).dump_to(writer);
    }
}

impl<'a, A: Dump> Dump for &'a mut A {
    fn dump_to<T: FrameTarget>(&self, writer: &mut FrameWriter<T>) {
        (**self).dump_to(writer);
    }
}

impl Dump for bool {
    fn dump_to<T: FrameTarget>(&self, writer: &mut FrameWriter<T>) {
        writer.write(if *self { 1u8 } else { 0u8 }); // TODO: write one bit
    }
}

impl<'a> Grab<'a> for bool {
    fn grab_from(reader: &mut FrameReader<'a>) -> Option<Self> {
        let me: u8 = reader.read()?;
        Some(me != 0)
    }
}

impl_for_numeric_multi! {
    (1, u8 ),
    (2, u16),
    (4, u32),
    (8, u64),
    (1, i8 ),
    (2, i16),
    (4, i32),
    (8, i64),
    (4, f32),
    (8, f64),
}

impl_for_tuple_multi! {
    (a A, b B),
    (a A, b B, c C),
    (a A, b B, c C, d D),
    (a A, b B, c C, d D, e E),
    (a A, b B, c C, d D, e E, f F),
    (a A, b B, c C, d D, e E, f F, g G),
    (a A, b B, c C, d D, e E, f F, g G, h H),
    (a A, b B, c C, d D, e E, f F, g G, h H, i I),
    (a A, b B, c C, d D, e E, f F, g G, h H, i I, j J),
}