internet 0.0.5

Network library for rust
Documentation
//!

use crate::{Buf, BufError, BufMut, BufResult, Codec, Cursor};

///
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct u24(pub u32);

impl Codec for u24 {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        writer.write_u8((self.0 >> 16) as u8)?;
        writer.write_u8((self.0 >> 8) as u8)?;
        writer.write_u8(self.0 as u8)?;
        Ok(())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        let b0 = reader.read_u8()? as u32;
        let b1 = reader.read_u8()? as u32;
        let b2 = reader.read_u8()? as u32;
        Ok(u24((b0 << 16) | (b1 << 8) | b2))
    }
}

impl From<u32> for u24 {
    fn from(val: u32) -> Self {
        u24(val & 0x00FF_FFFF)
    }
}
impl From<u24> for usize {
    fn from(val: u24) -> Self {
        val.0 as usize
    }
}

///
pub trait LengthPrefix: Codec {
    ///
    fn as_usize(&self) -> usize;
    ///
    fn from_usize(val: usize) -> BufResult<Self>;
}

impl LengthPrefix for u8 {
    fn as_usize(&self) -> usize {
        *self as usize
    }
    fn from_usize(val: usize) -> BufResult<Self> {
        val.try_into().map_err(|_| BufError::InvalidLength)
    }
}

impl LengthPrefix for u16 {
    fn as_usize(&self) -> usize {
        *self as usize
    }
    fn from_usize(val: usize) -> BufResult<Self> {
        val.try_into().map_err(|_| BufError::InvalidLength)
    }
}

impl LengthPrefix for u24 {
    fn as_usize(&self) -> usize {
        self.0 as usize
    }
    fn from_usize(val: usize) -> BufResult<Self> {
        if val > 0x00FF_FFFF {
            return Err(BufError::InvalidLength);
        }
        Ok(u24(val as u32))
    }
}

use std::marker::PhantomData;

///
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TlsVec<T, P> {
    ///
    pub items: Vec<T>,
    _marker: PhantomData<P>,
}

impl<T, P> TlsVec<T, P> {
    ///
    pub fn new(items: Vec<T>) -> Self {
        Self {
            items,
            _marker: PhantomData,
        }
    }
}

impl<T: Codec, P: LengthPrefix> Codec for TlsVec<T, P> {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        let mut prefix = P::from_usize(0)?;
        let initial_cursor_position = writer.position();
        prefix.encode(writer, ())?;
        let mid_position = writer.position();
        let prefix_length = mid_position as isize - initial_cursor_position as isize;
        if prefix_length < 0 {
            return Err(BufError::UnexpectedValue);
        }

        for item in &self.items {
            item.encode(writer, ())?;
        }

        let last_position = writer.position();
        let data_length = last_position as isize - mid_position as isize;
        if data_length < 0 {
            return Err(BufError::UnexpectedValue);
        }
        writer.rewind(data_length as usize + prefix_length as usize)?;
        prefix = P::from_usize(data_length as usize)?;
        prefix.encode(writer, ())?;
        writer.advance(data_length as usize)?;
        Ok(())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        let prefix = P::decode(reader, ())?;
        let expected_bytes = prefix.as_usize();

        let start_pos = reader.position();
        let mut items = Vec::new();

        while reader.position() - start_pos < expected_bytes {
            items.push(T::decode(reader, ())?);
        }

        if reader.position() - start_pos > expected_bytes {
            return Err(BufError::InvalidLength);
        }

        Ok(TlsVec::new(items))
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test() {}
}