synta/traits/convenience.rs
1//! Convenience traits for encoding/decoding without explicit Encoder/Decoder construction
2//!
3//! These traits provide `to_der()`, `to_ber()`, `from_der()`, and `from_ber()`
4//! methods on any type that implements [`Encode`] or [`Decode`], eliminating
5//! boilerplate for the common single-value encode/decode case.
6//!
7//! Both traits are blanket-implemented, so they are automatically available on
8//! all conforming types — including codegen-generated structs.
9//!
10//! # `from_der` / `from_ber` and lifetimes
11//!
12//! [`FromDer`] is blanket-implemented for `T: for<'a> Decode<'a>` — that is,
13//! types that own all their data after decoding (e.g. `Integer`, `Boolean`,
14//! `OctetString`, `ObjectIdentifier`, codegen structs using owned string
15//! types). Zero-copy borrowed types such as `OctetStringRef<'a>` cannot
16//! satisfy the HRTB bound; use [`Decoder`] directly for those.
17//!
18//! [`Decoder`]: crate::Decoder
19
20#[cfg(not(feature = "std"))]
21use alloc::vec::Vec;
22
23use crate::der::decoder::Decoder;
24use crate::der::encoder::Encoder;
25use crate::error::{Error, Result};
26use crate::traits::decode::Decode;
27use crate::traits::encode::Encode;
28use crate::Encoding;
29
30/// Encode a value to DER or BER bytes without constructing an [`Encoder`] manually.
31///
32/// Blanket-implemented for all types that implement [`Encode`].
33///
34/// # Examples
35///
36/// ```
37/// use synta::{Integer, ToDer};
38///
39/// let n = Integer::from_i64(42);
40/// let der = n.to_der().unwrap();
41/// assert_eq!(der, &[0x02, 0x01, 0x2A]);
42/// ```
43pub trait ToDer: Encode + Sized {
44 /// Encode `self` to DER and return the bytes.
45 fn to_der(&self) -> Result<Vec<u8>> {
46 let mut enc = Encoder::new(Encoding::Der);
47 enc.encode(self)?;
48 enc.finish()
49 }
50
51 /// Encode `self` to BER and return the bytes.
52 fn to_ber(&self) -> Result<Vec<u8>> {
53 let mut enc = Encoder::new(Encoding::Ber);
54 enc.encode(self)?;
55 enc.finish()
56 }
57}
58
59/// Blanket implementation of [`ToDer`] for all types that implement [`Encode`].
60///
61/// This impl is what makes `to_der()` and `to_ber()` available on every
62/// ASN.1 type in this crate — including types produced by `#[derive(Asn1Sequence)]`
63/// and friends — without any additional boilerplate.
64impl<T: Encode> ToDer for T {}
65
66/// Decode a value from a DER or BER byte slice without constructing a [`Decoder`] manually.
67///
68/// Blanket-implemented for all owned types `T` that satisfy `for<'a> Decode<'a>`.
69/// Zero-copy borrowed types (e.g. `OctetStringRef<'a>`) do not satisfy this
70/// bound; use [`Decoder`] directly for those.
71///
72/// Both methods require that the input contains **exactly** one TLV — trailing
73/// bytes cause [`Error::TrailingData`].
74///
75/// # Examples
76///
77/// ```
78/// use synta::{Integer, FromDer};
79///
80/// let der = &[0x02, 0x01, 0x2A]; // INTEGER 42
81/// let n = Integer::from_der(der).unwrap();
82/// assert_eq!(n.as_i64().unwrap(), 42);
83/// ```
84///
85/// ```
86/// use synta::{ObjectIdentifier, FromDer, ToDer};
87///
88/// let oid = ObjectIdentifier::new(&[1, 2, 840, 113549]).unwrap();
89/// let der = oid.to_der().unwrap();
90/// let oid2 = ObjectIdentifier::from_der(&der).unwrap();
91/// assert_eq!(oid, oid2);
92/// ```
93pub trait FromDer: Sized {
94 /// Decode one value from DER-encoded `input`.
95 ///
96 /// Returns [`Error::TrailingData`] if the input contains bytes beyond
97 /// the end of the decoded TLV.
98 fn from_der(input: &[u8]) -> Result<Self>;
99
100 /// Decode one value from BER-encoded `input`.
101 ///
102 /// Returns [`Error::TrailingData`] if the input contains bytes beyond
103 /// the end of the decoded TLV.
104 fn from_ber(input: &[u8]) -> Result<Self>;
105}
106
107/// Blanket implementation of [`FromDer`] for all fully-owned types.
108///
109/// The HRTB bound `T: for<'a> Decode<'a>` ensures that the type does not
110/// borrow from the input buffer. Zero-copy types such as `OctetStringRef<'a>`
111/// carry a lifetime tied to the buffer and therefore do not satisfy the bound;
112/// use [`Decoder`] directly for those.
113///
114/// [`Decoder`]: crate::Decoder
115impl<T: for<'a> Decode<'a>> FromDer for T {
116 fn from_der(input: &[u8]) -> Result<Self> {
117 let mut dec = Decoder::new(input, Encoding::Der);
118 let val = dec.decode()?;
119 if !dec.is_empty() {
120 return Err(Error::TrailingData {
121 position: dec.position(),
122 });
123 }
124 Ok(val)
125 }
126
127 fn from_ber(input: &[u8]) -> Result<Self> {
128 let mut dec = Decoder::new(input, Encoding::Ber);
129 let val = dec.decode()?;
130 if !dec.is_empty() {
131 return Err(Error::TrailingData {
132 position: dec.position(),
133 });
134 }
135 Ok(val)
136 }
137}