der/
decode.rs

1//! Trait definition for [`Decode`].
2
3use crate::{FixedTag, Header, Reader, Result, SliceReader};
4
5#[cfg(feature = "pem")]
6use crate::{pem::PemLabel, PemReader};
7
8#[cfg(doc)]
9use crate::{Length, Tag};
10
11/// Decoding trait.
12///
13/// This trait provides the core abstraction upon which all decoding operations
14/// are based.
15pub trait Decode<'a>: Sized {
16    /// Attempt to decode this message using the provided decoder.
17    fn decode<R: Reader<'a>>(decoder: &mut R) -> Result<Self>;
18
19    /// Parse `Self` from the provided DER-encoded byte slice.
20    fn from_der(bytes: &'a [u8]) -> Result<Self> {
21        let mut reader = SliceReader::new(bytes)?;
22        let result = Self::decode(&mut reader)?;
23        reader.finish(result)
24    }
25}
26
27impl<'a, T> Decode<'a> for T
28where
29    T: DecodeValue<'a> + FixedTag,
30{
31    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<T> {
32        let header = Header::decode(reader)?;
33        header.tag.assert_eq(T::TAG)?;
34        T::decode_value(reader, header)
35    }
36}
37
38/// Marker trait for data structures that can be decoded from DER without
39/// borrowing any data from the decoder.
40///
41/// This is primarily useful for trait bounds on functions which require that
42/// no data is borrowed from the decoder, for example a PEM decoder which needs
43/// to first decode data from Base64.
44///
45/// This trait is inspired by the [`DeserializeOwned` trait from `serde`](https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html).
46pub trait DecodeOwned: for<'a> Decode<'a> {}
47
48impl<T> DecodeOwned for T where T: for<'a> Decode<'a> {}
49
50/// PEM decoding trait.
51///
52/// This trait is automatically impl'd for any type which impls both
53/// [`DecodeOwned`] and [`PemLabel`].
54#[cfg(feature = "pem")]
55#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
56pub trait DecodePem: DecodeOwned + PemLabel {
57    /// Try to decode this type from PEM.
58    fn from_pem(pem: impl AsRef<[u8]>) -> Result<Self>;
59}
60
61#[cfg(feature = "pem")]
62#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
63impl<T: DecodeOwned + PemLabel> DecodePem for T {
64    fn from_pem(pem: impl AsRef<[u8]>) -> Result<Self> {
65        let mut reader = PemReader::new(pem.as_ref())?;
66        Self::validate_pem_label(reader.type_label())?;
67        T::decode(&mut reader)
68    }
69}
70
71/// Decode the value part of a Tag-Length-Value encoded field, sans the [`Tag`]
72/// and [`Length`].
73pub trait DecodeValue<'a>: Sized {
74    /// Attempt to decode this message using the provided [`Reader`].
75    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self>;
76}