keebrs 0.3.0

Keyboard firmware building blocks
//! Generic codec for no_std async io streams

use core::marker::PhantomData;

use serde::{
    de::DeserializeOwned,
    Serialize,
};

use embrio_core::io::{
    Read,
    Write,
};

use async_codec::{
    Decode,
    DecodeResult,
    Encode,
    EncodeResult,
    Framed,
};

/// Codec for arbitrary types via PostCard
pub struct PostCardCodec<T> {
    _ph: PhantomData<T>,
}

impl<T> Default for PostCardCodec<T> {
    fn default() -> Self {
        Self {
            _ph: Default::default(),
        }
    }
}

impl<T> PostCardCodec<T>
where
    T: DeserializeOwned,
{
    /// Wrap a [Read] to create a stream of messages
    pub fn stream<S: Read, B: Default + AsRef<[u8]> + AsMut<[u8]>>(
        stream: S,
    ) -> Framed<S, Self, B> {
        Framed::new(stream, Self::default(), B::default())
    }
}

impl<T> PostCardCodec<T> {
    /// Wrap a stream to create a sink or stream for messages
    pub fn framed<S, B: Default + AsRef<[u8]> + AsMut<[u8]>>(stream: S) -> Framed<S, Self, B> {
        Framed::new(stream, Self::default(), B::default())
    }
}

impl<T> PostCardCodec<T>
where
    T: Serialize,
{
    /// Wrap a [Write] to create a sink for messages
    pub fn sink<S: Write, B: Default + AsRef<[u8]> + AsMut<[u8]>>(stream: S) -> Framed<S, Self, B> {
        Framed::new(stream, Self::default(), B::default())
    }
}

impl<T> Encode for PostCardCodec<T>
where
    T: Serialize,
{
    type Item = T;
    type Error = postcard::Error;

    fn encode(&mut self, item: &T, buf: &mut [u8]) -> EncodeResult<Self::Error> {
        match postcard::to_slice_cobs(item, buf) {
            Ok(buf) => Ok(buf.len()).into(),
            Err(postcard::Error::SerializeBufferFull) => EncodeResult::Overflow(0),
            Err(e) => Err(e).into(),
        }
    }
}

impl<T> Decode for PostCardCodec<T>
where
    T: DeserializeOwned,
{
    type Item = T;
    type Error = postcard::Error;

    fn decode(&mut self, buf: &mut [u8]) -> (usize, DecodeResult<T, postcard::Error>) {
        let end = match buf.iter().position(|b| *b == 0x00) {
            Some(pos) => pos + 1,
            None => return (0, DecodeResult::UnexpectedEnd),
        };

        (end, postcard::from_bytes_cobs(&mut buf[..end]).into())
    }
}