oxidef_compact1 0.1.0-alpha.1

Oxidef is an experimental interface definition language and serialisation scheme for efficient and strongly-typed payloads.
Documentation
use bytes::BufMut;

use crate::{codec::Compact1Codec, decoder::DecError};

// Encode a JS int in 7 bits.
impl Compact1Codec for js_int::Int {
    fn encode<B: crate::encoder::ImprovidentBufMut>(
        &self,
        encoder: &mut crate::encoder::Encoder<B>,
    ) -> Result<(), crate::encoder::EncError>
    where
        Self: Sized,
    {
        // The extra 8th byte will either be all zero (non-negative numbers)
        // or all one (negative numbers)
        let byte_repr = &i64::from(*self).to_le_bytes()[0..7];
        encoder.buf.put_slice(&byte_repr);
        Ok(())
    }

    fn decode<B: crate::decoder::MeasureBuf>(
        decoder: &mut crate::decoder::Decoder<B>,
    ) -> Result<Self, DecError>
    where
        Self: Sized,
    {
        // Decoding is a bit trickier, because we need to length-extend the integer
        // in case it's negative...
        let mut byte_repr = [0u8; 8];
        decoder.buf.try_copy_to_slice(&mut byte_repr[0..7])?;

        if byte_repr[6] & 0b1000_0000 == 0b1000_0000 {
            byte_repr[7] = 0xFF;
        }

        let int = i64::from_le_bytes(byte_repr);

        js_int::Int::new(int).ok_or(DecError::InteropIntInvalid)
    }
}

impl Compact1Codec for js_int::UInt {
    fn encode<B: crate::encoder::ImprovidentBufMut>(
        &self,
        encoder: &mut crate::encoder::Encoder<B>,
    ) -> Result<(), crate::encoder::EncError>
    where
        Self: Sized,
    {
        // The extra 8th byte will be all zero, so we don't need to encode it
        let byte_repr = &u64::from(*self).to_le_bytes()[0..7];
        encoder.buf.put_slice(&byte_repr);
        Ok(())
    }

    fn decode<B: crate::decoder::MeasureBuf>(
        decoder: &mut crate::decoder::Decoder<B>,
    ) -> Result<Self, crate::decoder::DecError>
    where
        Self: Sized,
    {
        let mut byte_repr = [0u8; 8];
        decoder.buf.try_copy_to_slice(&mut byte_repr[0..7])?;
        let uint = u64::from_le_bytes(byte_repr);
        js_int::UInt::new(uint).ok_or(DecError::InteropIntInvalid)
    }
}