use crate::{
asn1::*, ByteSlice, Choice, Decodable, DecodeValue, Decoder, DerOrd, EncodeValue, Encoder,
Error, ErrorKind, FixedTag, Header, Length, Result, Tag, Tagged, ValueOrd,
};
use core::cmp::Ordering;
#[cfg(feature = "oid")]
use crate::asn1::ObjectIdentifier;
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Any<'a> {
tag: Tag,
value: ByteSlice<'a>,
}
impl<'a> Any<'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_bytes()
}
pub fn decode_into<T>(self) -> Result<T>
where
T: DecodeValue<'a> + FixedTag,
{
self.tag.assert_eq(T::TAG)?;
let mut decoder = Decoder::new(self.value())?;
let result = T::decode_value(&mut decoder, self.value.len())?;
decoder.finish(result)
}
pub fn is_null(self) -> bool {
self == Self::NULL
}
pub fn bit_string(self) -> Result<BitString<'a>> {
self.try_into()
}
pub fn context_specific<T>(self) -> Result<ContextSpecific<T>>
where
T: Decodable<'a>,
{
self.try_into()
}
pub fn generalized_time(self) -> Result<GeneralizedTime> {
self.try_into()
}
pub fn ia5_string(self) -> Result<Ia5String<'a>> {
self.try_into()
}
pub fn octet_string(self) -> Result<OctetString<'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<PrintableString<'a>> {
self.try_into()
}
pub fn sequence<F, T>(self, f: F) -> Result<T>
where
F: FnOnce(&mut Decoder<'a>) -> Result<T>,
{
self.tag.assert_eq(Tag::Sequence)?;
let mut seq_decoder = Decoder::new(self.value.as_bytes())?;
let result = f(&mut seq_decoder)?;
seq_decoder.finish(result)
}
pub fn utc_time(self) -> Result<UtcTime> {
self.try_into()
}
pub fn utf8_string(self) -> Result<Utf8String<'a>> {
self.try_into()
}
}
impl<'a> Choice<'a> for Any<'a> {
fn can_decode(_: Tag) -> bool {
true
}
}
impl<'a> Decodable<'a> for Any<'a> {
fn decode(decoder: &mut Decoder<'a>) -> Result<Any<'a>> {
let header = Header::decode(decoder)?;
let tag = header.tag;
let value = ByteSlice::decode_value(decoder, header.length)?;
Ok(Self { tag, value })
}
}
impl EncodeValue for Any<'_> {
fn value_len(&self) -> Result<Length> {
Ok(self.value.len())
}
fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> {
encoder.bytes(self.value())
}
}
impl Tagged for Any<'_> {
fn tag(&self) -> Tag {
self.tag
}
}
impl ValueOrd for Any<'_> {
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
self.value.der_cmp(&other.value)
}
}
impl<'a> From<Any<'a>> for ByteSlice<'a> {
fn from(any: Any<'a>) -> ByteSlice<'a> {
any.value
}
}
impl<'a> TryFrom<&'a [u8]> for Any<'a> {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Any<'a>> {
Any::from_der(bytes)
}
}