byten 0.0.13

A binary codec library for efficient encoding and decoding of data structures
Documentation
use core::{iter, marker::PhantomData};

use crate::{DecodeError, Decoder, EncodeError, Encoder, Measurer};

pub struct PrefixedCodec<Collection, Length, Item> {
    pub collection: PhantomData<Collection>,
    pub length: Length,
    pub item: Item,
}

impl<Collection, Length, Item> PrefixedCodec<Collection, Length, Item> {
    pub const fn new(length: Length, item: Item) -> Self {
        Self {
            collection: PhantomData,
            length,
            item,
        }
    }
}

impl<'encoded, 'decoded, 'length, Collection, Length, ItemCodec, Item> Decoder<'encoded, 'decoded>
    for PrefixedCodec<Collection, Length, ItemCodec>
where
    Collection: FromIterator<Item> + 'decoded,
    ItemCodec: Decoder<'encoded, 'decoded, Decoded = Item>,
    Length: Decoder<'encoded, 'length>,
    Length::Decoded: TryInto<usize>,
    <Length::Decoded as TryInto<usize>>::Error: Into<DecodeError>,
{
    type Decoded = Collection;

    fn decode(
        &self,
        encoded: &'encoded [u8],
        offset: &mut usize,
    ) -> Result<Self::Decoded, DecodeError> {
        let length_decoded = self.length.decode(encoded, offset)?;
        let length: usize = length_decoded.try_into().map_err(Into::into)?;

        let items = iter::from_fn(|| Some(self.item.decode(encoded, offset))).take(length);

        items.collect()
    }
}

impl<Collection, Length, ItemCodec> Measurer for PrefixedCodec<Collection, Length, ItemCodec>
where
    ItemCodec: Measurer,
    for<'decoded> &'decoded Collection: IntoIterator<Item = &'decoded ItemCodec::Decoded>,
    Length: Measurer,
    Length::Decoded: TryFrom<usize>,
    <Length::Decoded as TryFrom<usize>>::Error: Into<EncodeError>,
{
    type Decoded = Collection;

    fn measure(&self, decoded: &Collection) -> Result<usize, EncodeError> {
        let length = decoded.into_iter().count();
        let length: Length::Decoded = length.try_into().map_err(Into::into)?;
        let length_size = self.length.measure(&length)?;
        let items_size =
            decoded
                .into_iter()
                .try_fold(0usize, |acc, item| -> Result<_, EncodeError> {
                    let item_size = self.item.measure(item)?;
                    Ok(acc + item_size)
                })?;
        Ok(length_size + items_size)
    }
}

impl<Collection, Length, ItemCodec> Encoder for PrefixedCodec<Collection, Length, ItemCodec>
where
    ItemCodec: Encoder,
    for<'decoded> &'decoded Collection: IntoIterator<Item = &'decoded ItemCodec::Decoded>,
    Length: Encoder,
    Length::Decoded: TryFrom<usize>,
    <Length::Decoded as TryFrom<usize>>::Error: Into<EncodeError>,
{
    type Decoded = Collection;

    fn encode(
        &self,
        decoded: &Self::Decoded,
        encoded: &mut [u8],
        offset: &mut usize,
    ) -> Result<(), EncodeError> {
        let length = decoded.into_iter().count();
        let length: Length::Decoded = length.try_into().map_err(Into::into)?;
        self.length.encode(&length, encoded, offset)?;

        for item in decoded.into_iter() {
            self.item.encode(item, encoded, offset)?;
        }

        Ok(())
    }
}