codec 0.0.7

Codec trait to assist in making codecs
Documentation
use crate::{codec::{Codec, DecodeError, EncodeError}, impls::SizeContext};
use crate::buffers::{ EncodeBuffer, DecodeBuffer };

impl Codec<SizeContext> for std::string::String {
    fn encode(self, buf: &mut impl EncodeBuffer, ctx: SizeContext) -> Result<(), EncodeError> {
        match ctx {
            SizeContext::Fixed(usize) => {
                let slice = self.as_bytes();
                let length = slice.len();
                if length > usize {return Err(EncodeError::Encoding)}
                buf.push_slice(self.as_bytes())?;
                buf.push_slice(vec![0;usize-length].as_slice())
            },
            SizeContext::U8Len => {
                let slice = self.as_bytes();
                let length = u8::try_from(slice.len()).or_else(|_| Err(EncodeError::Encoding))?;
                buf.push(length)?;
                buf.push_slice(self.as_bytes())
            },
            SizeContext::U16Len(end) => {
                let slice = self.as_bytes();
                let length = u16::try_from(slice.len()).or_else(|_| Err(EncodeError::Encoding))?;
                length.encode(buf, end)?;
                buf.push_slice(self.as_bytes())
            },
            SizeContext::U32Len(end) => {
                let slice = self.as_bytes();
                let length = u32::try_from(slice.len()).or_else(|_| Err(EncodeError::Encoding))?;
                length.encode(buf, end)?;
                buf.push_slice(self.as_bytes())
            },
            SizeContext::NullTerminated => {
                buf.push_slice(self.as_bytes())?;
                buf.push(0)
            },
        }
    }
    fn decode(buf: &mut impl DecodeBuffer, ctx: SizeContext) -> Result<Self, DecodeError> {
        match ctx {
            SizeContext::Fixed(size) => {
                let mut slice = vec![0;size].into_boxed_slice();
                buf.read_slice(&mut slice)?;
                String::from_utf8(slice.to_vec()).or_else(|_| Err(DecodeError::Invalid))
            }
            SizeContext::U8Len => {
                let len = u8::decode(buf, ())?;
                let len = len as usize;
                let mut slice = vec![0;len].into_boxed_slice();
                buf.read_slice(&mut slice)?;
                String::from_utf8(slice.to_vec()).or_else(|_| Err(DecodeError::Invalid))
            }
            SizeContext::U16Len(end) => {
                let len = u16::decode(buf, end)?;
                let len = len as usize;
                let mut slice = vec![0;len].into_boxed_slice();
                buf.read_slice(&mut slice)?;
                String::from_utf8(slice.to_vec()).or_else(|_| Err(DecodeError::Invalid))
            }
            SizeContext::U32Len(end) => {
                let len = u32::decode(buf, end)?;
                let len = len as usize;
                let mut slice = vec![0;len].into_boxed_slice();
                buf.read_slice(&mut slice)?;
                String::from_utf8(slice.to_vec()).or_else(|_| Err(DecodeError::Invalid))
            }
            SizeContext::NullTerminated => {
                let mut vec = Vec::new();
                loop {
                    let char = u8::decode(buf, ())?;
                    if char == 0 {break}
                    vec.push(char);
                }
                String::from_utf8(vec).or_else(|_| Err(DecodeError::Invalid))
            }
        }
    }
}

impl<T: Copy + Codec<()>> Codec<SizeContext> for Vec<T> {
    fn encode(self, buf: & mut impl EncodeBuffer, ctx: SizeContext) -> Result<(), EncodeError> {
        match ctx {
            SizeContext::Fixed(len) => if len != self.len() {return Err(EncodeError::Encoding)},
            SizeContext::U8Len => (self.len() as u8).encode(buf, ())?,
            SizeContext::U16Len(endian) => (self.len() as u16).encode(buf, endian)?,
            SizeContext::U32Len(endian) => (self.len() as u32).encode(buf, endian)?,
            SizeContext::NullTerminated => unimplemented!("Not reasonable"),
        };
        for i in self {
            i.encode(buf, ())?;
        }

        Ok(())
    }
    fn decode(buf: &mut impl DecodeBuffer, ctx: SizeContext) -> Result<Self, DecodeError> {
        let size = match ctx {
            SizeContext::Fixed(len) => len,
            SizeContext::U8Len => u8::decode(buf, ())? as usize,
            SizeContext::U16Len(endian) => u16::decode(buf, endian)? as usize,
            SizeContext::U32Len(endian) => u32::decode(buf, endian)? as usize,
            SizeContext::NullTerminated => unimplemented!("Not reasonable"),
        };

        let mut result = Vec::with_capacity(size);
        for _ in 0..size {
            result.push(T::decode(buf, ())?);
        }

        Ok(result)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{buffers::*, Endian};

    #[test]
    fn decode_string_null_terminated() {
        let mut slice = [b'h', b'e', b'l', b'l', b'o', 0];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::decode(&mut buf, SizeContext::NullTerminated).unwrap();
        assert_eq!(string, "hello");
    }

    #[test]
    fn decode_string_fixed() {
        let mut slice = [b'h', b'e', b'l', b'l', b'o'];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::decode(&mut buf, SizeContext::Fixed(5)).unwrap();
        assert_eq!(string, "hello");
    }

    #[test]
    fn decode_string_u8len() {
        let mut slice = [5, b'h', b'e', b'l', b'l', b'o'];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::decode(&mut buf, SizeContext::U8Len).unwrap();
        assert_eq!(string, "hello");
    }

    #[test]
    fn decode_string_u16len() {
        let mut slice = [5, 0, b'h', b'e', b'l', b'l', b'o'];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::decode(&mut buf, SizeContext::U16Len(Endian::Little)).unwrap();
        assert_eq!(string, "hello");
    }

    #[test]
    fn decode_string_u32len() {
        let mut slice = [5, 0, 0, 0, b'h', b'e', b'l', b'l', b'o'];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::decode(&mut buf, SizeContext::U32Len(Endian::Little)).unwrap();
        assert_eq!(string, "hello");
    }

    #[test]
    fn encode_string_null_terminated() {
        let mut slice = [0;6];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::from("hello");
        string.encode(&mut buf, SizeContext::NullTerminated).unwrap();
        assert_eq!(slice, [b'h', b'e', b'l', b'l', b'o', 0]);
    }

    #[test]
    fn encode_string_fixed() {
        let mut slice = [0;5];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::from("hello");
        string.encode(&mut buf, SizeContext::Fixed(5)).unwrap();
        assert_eq!(slice, [b'h', b'e', b'l', b'l', b'o']);
    }

    #[test]
    fn encode_string_u8len() {
        let mut slice = [0;6];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::from("hello");
        string.encode(&mut buf, SizeContext::U8Len).unwrap();
        assert_eq!(slice, [5, b'h', b'e', b'l', b'l', b'o']);
    }

    #[test]
    fn encode_string_u16len() {
        let mut slice = [0;7];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::from("hello");
        string.encode(&mut buf, SizeContext::U16Len(Endian::Little)).unwrap();
        assert_eq!(slice, [5, 0, b'h', b'e', b'l', b'l', b'o']);
    }

    #[test]
    fn encode_string_u32len() {
        let mut slice = [0;9];
        let mut buf = StaticBuffer::new(&mut slice);
        let string = String::from("hello");
        string.encode(&mut buf, SizeContext::U32Len(Endian::Little)).unwrap();
        assert_eq!(slice, [5, 0, 0, 0, b'h', b'e', b'l', b'l', b'o']);
    }
}