use crate::{Error, FixedTag, Header, Reader, SliceReader, reader::read_value};
use core::marker::PhantomData;
#[cfg(feature = "pem")]
use crate::{PemReader, pem::PemLabel};
#[cfg(doc)]
use crate::{ErrorKind, Length, Tag};
#[cfg(feature = "alloc")]
use alloc::{
borrow::{Cow, ToOwned},
boxed::Box,
};
#[cfg(feature = "ber")]
use crate::EncodingRules;
#[diagnostic::on_unimplemented(
note = "Consider adding impls of `DecodeValue` and `FixedTag` to `{Self}`"
)]
pub trait Decode<'a>: Sized + 'a {
type Error: core::error::Error + From<Error> + 'static;
fn decode<R: Reader<'a>>(decoder: &mut R) -> Result<Self, Self::Error>;
#[cfg(feature = "ber")]
fn from_ber(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let mut reader = SliceReader::new_with_encoding_rules(bytes, EncodingRules::Ber)?;
let result = Self::decode(&mut reader)?;
reader.finish()?;
Ok(result)
}
fn from_der(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let mut reader = SliceReader::new(bytes)?;
let result = Self::decode(&mut reader)?;
reader.finish()?;
Ok(result)
}
fn from_der_partial(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let mut reader = SliceReader::new(bytes)?;
let result = Self::decode(&mut reader)?;
let remaining = reader.remaining()?;
Ok((result, remaining))
}
}
impl<'a, T> Decode<'a> for T
where
T: DecodeValue<'a> + FixedTag + 'a,
{
type Error = <T as DecodeValue<'a>>::Error;
fn decode<R: Reader<'a>>(reader: &mut R) -> Result<T, <T as DecodeValue<'a>>::Error> {
let header = Header::decode(reader)?;
header.tag().assert_eq(T::TAG)?;
read_value(reader, header, T::decode_value)
}
}
impl<'a, T> Decode<'a> for PhantomData<T>
where
T: ?Sized + 'a,
{
type Error = Error;
fn decode<R: Reader<'a>>(_reader: &mut R) -> Result<PhantomData<T>, Error> {
Ok(PhantomData)
}
}
#[diagnostic::on_unimplemented(
note = "`DecodeOwned` is auto-impl'd for all lifetime-free types which impl `Decode`"
)]
pub trait DecodeOwned: for<'a> Decode<'a> {}
impl<T> DecodeOwned for T where T: for<'a> Decode<'a> {}
#[cfg(feature = "pem")]
#[diagnostic::on_unimplemented(
note = "`DecodePem` is auto-impl'd for all lifetime-free types which impl both `Decode` and `PemLabel`"
)]
pub trait DecodePem: DecodeOwned + PemLabel {
fn from_pem(pem: impl AsRef<[u8]>) -> Result<Self, <Self as Decode<'static>>::Error>;
}
#[cfg(feature = "pem")]
impl<T: DecodeOwned<Error = Error> + PemLabel> DecodePem for T {
fn from_pem(pem: impl AsRef<[u8]>) -> Result<T, Error> {
let mut reader = PemReader::new(pem.as_ref())?;
Self::validate_pem_label(reader.type_label()).map_err(Error::from)?;
T::decode(&mut reader)
}
}
pub trait DecodeValue<'a>: Sized {
type Error: core::error::Error + From<Error> + 'static;
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error>;
}
#[cfg(feature = "alloc")]
impl<'a, T> DecodeValue<'a> for Box<T>
where
T: DecodeValue<'a>,
{
type Error = T::Error;
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
Ok(Box::new(T::decode_value(reader, header)?))
}
}
#[cfg(feature = "alloc")]
impl<'a, T, E> DecodeValue<'a> for Cow<'a, T>
where
T: ToOwned + ?Sized,
&'a T: DecodeValue<'a, Error = E>,
T::Owned: for<'b> DecodeValue<'b, Error = E>,
E: core::error::Error + From<Error> + 'static,
{
type Error = E;
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
if R::CAN_READ_SLICE {
<&'a T>::decode_value(reader, header).map(Cow::Borrowed)
} else {
T::Owned::decode_value(reader, header).map(Cow::Owned)
}
}
}