use crate::{
asn1::*, ByteSlice, Choice, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind,
FixedTag, Header, Length, Reader, Result, SliceReader, Tag, Tagged, ValueOrd, Writer,
};
use core::cmp::Ordering;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "oid")]
use crate::asn1::ObjectIdentifier;
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct AnyRef<'a> {
tag: Tag,
value: ByteSlice<'a>,
}
impl<'a> AnyRef<'a> {
pub const NULL: Self = Self {
tag: Tag::Null,
value: ByteSlice::EMPTY,
};
pub fn new(tag: Tag, bytes: &'a [u8]) -> Result<Self> {
let value = ByteSlice::new(bytes).map_err(|_| ErrorKind::Length { tag })?;
Ok(Self { tag, value })
}
pub(crate) fn from_tag_and_value(tag: Tag, value: ByteSlice<'a>) -> Self {
Self { tag, value }
}
pub fn value(self) -> &'a [u8] {
self.value.as_slice()
}
pub fn decode_into<T>(self) -> Result<T>
where
T: DecodeValue<'a> + FixedTag,
{
self.tag.assert_eq(T::TAG)?;
let header = Header {
tag: self.tag,
length: self.value.len(),
};
let mut decoder = SliceReader::new(self.value())?;
let result = T::decode_value(&mut decoder, header)?;
decoder.finish(result)
}
pub fn is_null(self) -> bool {
self == Self::NULL
}
pub fn bit_string(self) -> Result<BitStringRef<'a>> {
self.try_into()
}
pub fn context_specific<T>(self) -> Result<ContextSpecific<T>>
where
T: Decode<'a>,
{
self.try_into()
}
pub fn generalized_time(self) -> Result<GeneralizedTime> {
self.try_into()
}
pub fn ia5_string(self) -> Result<Ia5StringRef<'a>> {
self.try_into()
}
pub fn octet_string(self) -> Result<OctetStringRef<'a>> {
self.try_into()
}
#[cfg(feature = "oid")]
#[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
pub fn oid(self) -> Result<ObjectIdentifier> {
self.try_into()
}
pub fn optional<T>(self) -> Result<Option<T>>
where
T: Choice<'a> + TryFrom<Self, Error = Error>,
{
if T::can_decode(self.tag) {
T::try_from(self).map(Some)
} else {
Ok(None)
}
}
pub fn printable_string(self) -> Result<PrintableStringRef<'a>> {
self.try_into()
}
pub fn teletex_string(self) -> Result<TeletexStringRef<'a>> {
self.try_into()
}
pub fn videotex_string(self) -> Result<VideotexStringRef<'a>> {
self.try_into()
}
pub fn sequence<F, T>(self, f: F) -> Result<T>
where
F: FnOnce(&mut SliceReader<'a>) -> Result<T>,
{
self.tag.assert_eq(Tag::Sequence)?;
let mut reader = SliceReader::new(self.value.as_slice())?;
let result = f(&mut reader)?;
reader.finish(result)
}
pub fn utc_time(self) -> Result<UtcTime> {
self.try_into()
}
pub fn utf8_string(self) -> Result<Utf8StringRef<'a>> {
self.try_into()
}
}
impl<'a> Choice<'a> for AnyRef<'a> {
fn can_decode(_: Tag) -> bool {
true
}
}
impl<'a> Decode<'a> for AnyRef<'a> {
fn decode<R: Reader<'a>>(reader: &mut R) -> Result<AnyRef<'a>> {
let header = Header::decode(reader)?;
Ok(Self {
tag: header.tag,
value: ByteSlice::decode_value(reader, header)?,
})
}
}
impl EncodeValue for AnyRef<'_> {
fn value_len(&self) -> Result<Length> {
Ok(self.value.len())
}
fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
writer.write(self.value())
}
}
impl Tagged for AnyRef<'_> {
fn tag(&self) -> Tag {
self.tag
}
}
impl ValueOrd for AnyRef<'_> {
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
self.value.der_cmp(&other.value)
}
}
impl<'a> From<AnyRef<'a>> for ByteSlice<'a> {
fn from(any: AnyRef<'a>) -> ByteSlice<'a> {
any.value
}
}
impl<'a> TryFrom<&'a [u8]> for AnyRef<'a> {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<AnyRef<'a>> {
AnyRef::from_der(bytes)
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Any {
tag: Tag,
value: Vec<u8>,
}
#[cfg(feature = "alloc")]
impl Any {
pub fn new(tag: Tag, bytes: impl Into<Vec<u8>>) -> Result<Self> {
let value = bytes.into();
AnyRef::new(tag, &value)?;
Ok(Self { tag, value })
}
}
#[cfg(feature = "alloc")]
impl Choice<'_> for Any {
fn can_decode(_: Tag) -> bool {
true
}
}
#[cfg(feature = "alloc")]
impl<'a> Decode<'a> for Any {
fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
let header = Header::decode(reader)?;
let value = reader.read_vec(header.length)?;
Self::new(header.tag, value)
}
}
#[cfg(feature = "alloc")]
impl EncodeValue for Any {
fn value_len(&self) -> Result<Length> {
self.value.len().try_into()
}
fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> {
writer.write(&self.value)
}
}
#[cfg(feature = "alloc")]
impl<'a> From<&'a Any> for AnyRef<'a> {
fn from(any: &'a Any) -> AnyRef<'a> {
AnyRef::new(any.tag, &any.value).expect("invalid ANY")
}
}
#[cfg(feature = "alloc")]
impl Tagged for Any {
fn tag(&self) -> Tag {
self.tag
}
}