use crate::{
asn1::{Asn1DecodeWrapper, Asn1EncodeWrapper, Asn1Error, INTEGER_TAG, Len, decode_asn1_tlv},
codec::{Decode, DecodeWrapper, Encode, EncodeWrapper, GenericCodec},
misc::Lease,
};
#[derive(Clone, Debug, PartialEq)]
pub struct Integer<B>(B);
impl<B> Integer<B>
where
B: Lease<[u8]>,
{
pub fn new(bytes: B) -> crate::Result<Self> {
check_bytes(bytes.lease())?;
Ok(Self(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(()),
}
}