codec 0.0.6

Codec trait to assist in making codecs
Documentation
use std::{boxed::Box, string::String};
use std::vec;
use std::vec::Vec;

use crate::{codec::{Codec, DecodeError, EncodeError}, impls::StringContext};
use crate::buffers::{ EncodeBuffer, DecodeBuffer };

impl Codec<StringContext> for std::string::String {
    fn encode(self, buf: &mut impl EncodeBuffer, ctx: StringContext) -> Result<(), EncodeError> {
        match ctx {
            StringContext::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())
            },
            StringContext::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())
            },
            StringContext::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())
            },
            StringContext::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())
            },
            StringContext::NullTerminated => {
                buf.push_slice(self.as_bytes())?;
                buf.push(0)
            },
        }
    }
    fn decode(buf: &mut impl DecodeBuffer, ctx: StringContext) -> Result<Self, DecodeError> {
        match ctx {
            StringContext::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))
            }
            StringContext::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))
            }
            StringContext::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))
            }
            StringContext::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))
            }
            StringContext::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))
            }
        }
    }
}

#[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, StringContext::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, StringContext::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, StringContext::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, StringContext::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, StringContext::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, StringContext::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, StringContext::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, StringContext::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, StringContext::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, StringContext::U32Len(Endian::Little)).unwrap();
        assert_eq!(slice, [5, 0, 0, 0, b'h', b'e', b'l', b'l', b'o']);
    }
}