pub(super) mod bigint;
mod int;
mod uint;
use crate::{
asn1::Any, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error, FixedTag, Length,
Result, Tag, ValueOrd,
};
use core::{cmp::Ordering, mem};
macro_rules! impl_int_encoding {
($($int:ty => $uint:ty),+) => {
$(
impl<'a> DecodeValue<'a> for $int {
fn decode_value(decoder: &mut Decoder<'a>, length: Length) -> Result<Self> {
let bytes = ByteSlice::decode_value(decoder, length)?.as_bytes();
let result = if is_highest_bit_set(bytes) {
<$uint>::from_be_bytes(int::decode_to_array(bytes)?) as $int
} else {
Self::from_be_bytes(uint::decode_to_array(bytes)?)
};
if length != result.value_len()? {
return Err(Self::TAG.non_canonical_error());
}
Ok(result)
}
}
impl EncodeValue for $int {
fn value_len(&self) -> Result<Length> {
if *self < 0 {
int::encoded_len(&(*self as $uint).to_be_bytes())
} else {
uint::encoded_len(&self.to_be_bytes())
}
}
fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> {
if *self < 0 {
int::encode_bytes(encoder, &(*self as $uint).to_be_bytes())
} else {
uint::encode_bytes(encoder, &self.to_be_bytes())
}
}
}
impl FixedTag for $int {
const TAG: Tag = Tag::Integer;
}
impl ValueOrd for $int {
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
value_cmp(*self, *other)
}
}
impl TryFrom<Any<'_>> for $int {
type Error = Error;
fn try_from(any: Any<'_>) -> Result<Self> {
any.decode_into()
}
}
)+
};
}
macro_rules! impl_uint_encoding {
($($uint:ty),+) => {
$(
impl<'a> DecodeValue<'a> for $uint {
fn decode_value(decoder: &mut Decoder<'a>, length: Length) -> Result<Self> {
let bytes = ByteSlice::decode_value(decoder, length)?.as_bytes();
let result = Self::from_be_bytes(uint::decode_to_array(bytes)?);
if length != result.value_len()? {
return Err(Self::TAG.non_canonical_error());
}
Ok(result)
}
}
impl EncodeValue for $uint {
fn value_len(&self) -> Result<Length> {
uint::encoded_len(&self.to_be_bytes())
}
fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> {
uint::encode_bytes(encoder, &self.to_be_bytes())
}
}
impl FixedTag for $uint {
const TAG: Tag = Tag::Integer;
}
impl ValueOrd for $uint {
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
value_cmp(*self, *other)
}
}
impl TryFrom<Any<'_>> for $uint {
type Error = Error;
fn try_from(any: Any<'_>) -> Result<Self> {
any.decode_into()
}
}
)+
};
}
impl_int_encoding!(i8 => u8, i16 => u16, i32 => u32, i64 => u64, i128 => u128);
impl_uint_encoding!(u8, u16, u32, u64, u128);
#[inline]
fn is_highest_bit_set(bytes: &[u8]) -> bool {
bytes
.get(0)
.map(|byte| byte & 0b10000000 != 0)
.unwrap_or(false)
}
fn value_cmp<T>(a: T, b: T) -> Result<Ordering>
where
T: Copy + EncodeValue + Sized,
{
const MAX_INT_SIZE: usize = 16;
debug_assert!(mem::size_of::<T>() <= MAX_INT_SIZE);
let mut buf1 = [0u8; MAX_INT_SIZE];
let mut encoder1 = Encoder::new(&mut buf1);
a.encode_value(&mut encoder1)?;
let mut buf2 = [0u8; MAX_INT_SIZE];
let mut encoder2 = Encoder::new(&mut buf2);
b.encode_value(&mut encoder2)?;
Ok(encoder1.finish()?.cmp(encoder2.finish()?))
}
#[cfg(test)]
pub(crate) mod tests {
use crate::{Decodable, Encodable};
pub(crate) const I0_BYTES: &[u8] = &[0x02, 0x01, 0x00];
pub(crate) const I127_BYTES: &[u8] = &[0x02, 0x01, 0x7F];
pub(crate) const I128_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0x80];
pub(crate) const I256_BYTES: &[u8] = &[0x02, 0x02, 0x01, 0x00];
pub(crate) const INEG128_BYTES: &[u8] = &[0x02, 0x01, 0x80];
pub(crate) const INEG129_BYTES: &[u8] = &[0x02, 0x02, 0xFF, 0x7F];
pub(crate) const I255_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0xFF];
pub(crate) const I32767_BYTES: &[u8] = &[0x02, 0x02, 0x7F, 0xFF];
pub(crate) const I65535_BYTES: &[u8] = &[0x02, 0x03, 0x00, 0xFF, 0xFF];
pub(crate) const INEG32768_BYTES: &[u8] = &[0x02, 0x02, 0x80, 0x00];
#[test]
fn decode_i8() {
assert_eq!(0, i8::from_der(I0_BYTES).unwrap());
assert_eq!(127, i8::from_der(I127_BYTES).unwrap());
assert_eq!(-128, i8::from_der(INEG128_BYTES).unwrap());
}
#[test]
fn decode_i16() {
assert_eq!(0, i16::from_der(I0_BYTES).unwrap());
assert_eq!(127, i16::from_der(I127_BYTES).unwrap());
assert_eq!(128, i16::from_der(I128_BYTES).unwrap());
assert_eq!(255, i16::from_der(I255_BYTES).unwrap());
assert_eq!(256, i16::from_der(I256_BYTES).unwrap());
assert_eq!(32767, i16::from_der(I32767_BYTES).unwrap());
assert_eq!(-128, i16::from_der(INEG128_BYTES).unwrap());
assert_eq!(-129, i16::from_der(INEG129_BYTES).unwrap());
assert_eq!(-32768, i16::from_der(INEG32768_BYTES).unwrap());
}
#[test]
fn decode_u8() {
assert_eq!(0, u8::from_der(I0_BYTES).unwrap());
assert_eq!(127, u8::from_der(I127_BYTES).unwrap());
assert_eq!(255, u8::from_der(I255_BYTES).unwrap());
}
#[test]
fn decode_u16() {
assert_eq!(0, u16::from_der(I0_BYTES).unwrap());
assert_eq!(127, u16::from_der(I127_BYTES).unwrap());
assert_eq!(255, u16::from_der(I255_BYTES).unwrap());
assert_eq!(256, u16::from_der(I256_BYTES).unwrap());
assert_eq!(32767, u16::from_der(I32767_BYTES).unwrap());
assert_eq!(65535, u16::from_der(I65535_BYTES).unwrap());
}
#[test]
fn encode_i8() {
let mut buffer = [0u8; 3];
assert_eq!(I0_BYTES, 0i8.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I127_BYTES, 127i8.encode_to_slice(&mut buffer).unwrap());
assert_eq!(
INEG128_BYTES,
(-128i8).encode_to_slice(&mut buffer).unwrap()
);
}
#[test]
fn encode_i16() {
let mut buffer = [0u8; 4];
assert_eq!(I0_BYTES, 0i16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I127_BYTES, 127i16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I128_BYTES, 128i16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I255_BYTES, 255i16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I256_BYTES, 256i16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I32767_BYTES, 32767i16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(
INEG128_BYTES,
(-128i16).encode_to_slice(&mut buffer).unwrap()
);
assert_eq!(
INEG129_BYTES,
(-129i16).encode_to_slice(&mut buffer).unwrap()
);
assert_eq!(
INEG32768_BYTES,
(-32768i16).encode_to_slice(&mut buffer).unwrap()
);
}
#[test]
fn encode_u8() {
let mut buffer = [0u8; 4];
assert_eq!(I0_BYTES, 0u8.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I127_BYTES, 127u8.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I255_BYTES, 255u8.encode_to_slice(&mut buffer).unwrap());
}
#[test]
fn encode_u16() {
let mut buffer = [0u8; 5];
assert_eq!(I0_BYTES, 0u16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I127_BYTES, 127u16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I128_BYTES, 128u16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I255_BYTES, 255u16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I256_BYTES, 256u16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I32767_BYTES, 32767u16.encode_to_slice(&mut buffer).unwrap());
assert_eq!(I65535_BYTES, 65535u16.encode_to_slice(&mut buffer).unwrap());
}
#[test]
fn reject_non_canonical() {
assert!(i8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
assert!(i16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
assert!(u8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
assert!(u16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err());
}
}