1use crate::{Header, Length, Result, SliceWriter, Tagged, Writer};
4use core::marker::PhantomData;
5
6#[cfg(feature = "alloc")]
7use {alloc::boxed::Box, alloc::vec::Vec, core::iter};
8
9#[cfg(feature = "pem")]
10use {
11 crate::PemWriter,
12 alloc::string::String,
13 pem_rfc7468::{self as pem, LineEnding, PemLabel},
14};
15
16#[cfg(any(feature = "alloc", feature = "pem"))]
17use crate::ErrorKind;
18
19#[cfg(doc)]
20use crate::Tag;
21
22pub trait Encode {
24 fn encoded_len(&self) -> Result<Length>;
26
27 fn encode(&self, encoder: &mut impl Writer) -> Result<()>;
29
30 fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
33 let mut writer = SliceWriter::new(buf);
34 self.encode(&mut writer)?;
35 writer.finish()
36 }
37
38 #[cfg(feature = "alloc")]
41 fn encode_to_vec(&self, buf: &mut Vec<u8>) -> Result<Length> {
42 let expected_len = usize::try_from(self.encoded_len()?)?;
43 buf.reserve(expected_len);
44 buf.extend(iter::repeat(0).take(expected_len));
45
46 let mut writer = SliceWriter::new(buf);
47 self.encode(&mut writer)?;
48 let actual_len = writer.finish()?.len();
49
50 if expected_len != actual_len {
51 return Err(ErrorKind::Incomplete {
52 expected_len: expected_len.try_into()?,
53 actual_len: actual_len.try_into()?,
54 }
55 .into());
56 }
57
58 actual_len.try_into()
59 }
60
61 #[cfg(feature = "alloc")]
63 fn to_der(&self) -> Result<Vec<u8>> {
64 let mut buf = Vec::new();
65 self.encode_to_vec(&mut buf)?;
66 Ok(buf)
67 }
68}
69
70impl<T> Encode for T
71where
72 T: EncodeValue + Tagged,
73{
74 fn encoded_len(&self) -> Result<Length> {
76 self.value_len().and_then(|len| len.for_tlv())
77 }
78
79 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
81 self.header()?.encode(writer)?;
82 self.encode_value(writer)
83 }
84}
85
86impl<T> Encode for PhantomData<T>
89where
90 T: ?Sized,
91{
92 fn encoded_len(&self) -> Result<Length> {
93 Ok(Length::ZERO)
94 }
95
96 fn encode(&self, _writer: &mut impl Writer) -> Result<()> {
97 Ok(())
98 }
99}
100
101#[cfg(feature = "pem")]
106pub trait EncodePem: Encode + PemLabel {
107 fn to_pem(&self, line_ending: LineEnding) -> Result<String>;
109}
110
111#[cfg(feature = "pem")]
112impl<T: Encode + PemLabel> EncodePem for T {
113 fn to_pem(&self, line_ending: LineEnding) -> Result<String> {
114 let der_len = usize::try_from(self.encoded_len()?)?;
115 let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, der_len)?;
116
117 let mut buf = vec![0u8; pem_len];
118 let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?;
119 self.encode(&mut writer)?;
120
121 let actual_len = writer.finish()?;
122 buf.truncate(actual_len);
123 Ok(String::from_utf8(buf)?)
124 }
125}
126
127pub trait EncodeValue {
130 fn header(&self) -> Result<Header>
132 where
133 Self: Tagged,
134 {
135 Header::new(self.tag(), self.value_len()?)
136 }
137
138 fn value_len(&self) -> Result<Length>;
141
142 fn encode_value(&self, encoder: &mut impl Writer) -> Result<()>;
145}
146
147#[cfg(feature = "alloc")]
148impl<T> EncodeValue for Box<T>
149where
150 T: EncodeValue,
151{
152 fn value_len(&self) -> Result<Length> {
153 T::value_len(self)
154 }
155 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
156 T::encode_value(self, writer)
157 }
158}