use super::uint;
use crate::{
asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind,
FixedTag, Header, Length, Reader, Result, Tag, Writer,
};
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct UIntRef<'a> {
inner: ByteSlice<'a>,
}
impl<'a> UIntRef<'a> {
pub fn new(bytes: &'a [u8]) -> Result<Self> {
let inner = ByteSlice::new(uint::strip_leading_zeroes(bytes))
.map_err(|_| ErrorKind::Length { tag: Self::TAG })?;
Ok(Self { inner })
}
pub fn as_bytes(&self) -> &'a [u8] {
self.inner.as_slice()
}
pub fn len(&self) -> Length {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}
impl<'a> DecodeValue<'a> for UIntRef<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
let bytes = ByteSlice::decode_value(reader, header)?.as_slice();
let result = Self::new(uint::decode_to_slice(bytes)?)?;
if result.value_len()? != header.length {
return Err(Self::TAG.non_canonical_error());
}
Ok(result)
}
}
impl<'a> EncodeValue for UIntRef<'a> {
fn value_len(&self) -> Result<Length> {
uint::encoded_len(self.inner.as_slice())
}
fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
if self.value_len()? > self.len() {
writer.write_byte(0)?;
}
writer.write(self.as_bytes())
}
}
impl<'a> From<&UIntRef<'a>> for UIntRef<'a> {
fn from(value: &UIntRef<'a>) -> UIntRef<'a> {
*value
}
}
impl<'a> TryFrom<AnyRef<'a>> for UIntRef<'a> {
type Error = Error;
fn try_from(any: AnyRef<'a>) -> Result<UIntRef<'a>> {
any.decode_into()
}
}
impl<'a> FixedTag for UIntRef<'a> {
const TAG: Tag = Tag::Integer;
}
impl<'a> OrdIsValueOrd for UIntRef<'a> {}
#[cfg(test)]
mod tests {
use super::UIntRef;
use crate::{
asn1::{integer::tests::*, AnyRef},
Decode, Encode, ErrorKind, SliceWriter, Tag,
};
#[test]
fn decode_uint_bytes() {
assert_eq!(&[0], UIntRef::from_der(I0_BYTES).unwrap().as_bytes());
assert_eq!(&[127], UIntRef::from_der(I127_BYTES).unwrap().as_bytes());
assert_eq!(&[128], UIntRef::from_der(I128_BYTES).unwrap().as_bytes());
assert_eq!(&[255], UIntRef::from_der(I255_BYTES).unwrap().as_bytes());
assert_eq!(
&[0x01, 0x00],
UIntRef::from_der(I256_BYTES).unwrap().as_bytes()
);
assert_eq!(
&[0x7F, 0xFF],
UIntRef::from_der(I32767_BYTES).unwrap().as_bytes()
);
}
#[test]
fn encode_uint_bytes() {
for &example in &[
I0_BYTES,
I127_BYTES,
I128_BYTES,
I255_BYTES,
I256_BYTES,
I32767_BYTES,
] {
let uint = UIntRef::from_der(example).unwrap();
let mut buf = [0u8; 128];
let mut encoder = SliceWriter::new(&mut buf);
uint.encode(&mut encoder).unwrap();
let result = encoder.finish().unwrap();
assert_eq!(example, result);
}
}
#[test]
fn reject_oversize_without_extra_zero() {
let err = UIntRef::try_from(AnyRef::new(Tag::Integer, &[0x81]).unwrap())
.err()
.unwrap();
assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer });
}
}