wtx 0.44.2

A collection of different transport implementations and related tools focused primarily on web technologies.
Documentation
use crate::{
  asn1::{Asn1DecodeWrapper, Asn1EncodeWrapper, Asn1Error, INTEGER_TAG, Len, decode_asn1_tlv},
  codec::{Decode, DecodeWrapper, Encode, EncodeWrapper, GenericCodec},
  misc::Lease,
};

/// Big-endian two's complement bytes
#[derive(Clone, Debug, PartialEq)]
pub struct Integer<B>(B);

impl<B> Integer<B>
where
  B: Lease<[u8]>,
{
  /// New instance that checks invalid data.
  pub fn new(bytes: B) -> crate::Result<Self> {
    check_bytes(bytes.lease())?;
    Ok(Self(bytes))
  }

  /// Bytes
  pub fn bytes(&self) -> &[u8] {
    self.0.lease()
  }
}

impl<'de> Decode<'de, GenericCodec<Asn1DecodeWrapper, ()>> for Integer<&'de [u8]> {
  #[inline]
  fn decode(dw: &mut DecodeWrapper<'de, Asn1DecodeWrapper>) -> crate::Result<Self> {
    let (INTEGER_TAG, _, bytes, rest) = decode_asn1_tlv(dw.bytes)? else {
      return Err(Asn1Error::InvalidInteger.into());
    };
    check_bytes(bytes)?;
    dw.bytes = rest;
    Ok(Self(bytes))
  }
}

impl<B> Encode<GenericCodec<(), Asn1EncodeWrapper>> for Integer<B>
where
  B: Lease<[u8]>,
{
  #[inline]
  fn encode(&self, ew: &mut EncodeWrapper<'_, Asn1EncodeWrapper>) -> crate::Result<()> {
    let bytes = self.0.lease();
    let _ = ew.buffer.extend_from_copyable_slices([
      &[INTEGER_TAG][..],
      &*Len::from_usize(0, self.0.lease().len())?,
      bytes,
    ])?;
    Ok(())
  }
}

fn check_bytes(bytes: &[u8]) -> crate::Result<()> {
  match bytes {
    [] => Err(Asn1Error::InvalidInteger.into()),
    [0, b, ..] if b & 0b1000_0000 == 0 => Err(Asn1Error::InvalidInteger.into()),
    [0b1111_1111, b, ..] if b & 0b1000_0000 != 0 => Err(Asn1Error::InvalidInteger.into()),
    _ => Ok(()),
  }
}