1use crate::{Header, Length, Result, SliceWriter, Tagged, Writer};
4use core::marker::PhantomData;
5
6#[cfg(feature = "alloc")]
7use {alloc::boxed::Box, alloc::vec::Vec};
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
22#[diagnostic::on_unimplemented(
24 note = "Consider adding impls of `EncodeValue` and `FixedTag` to `{Self}`"
25)]
26pub trait Encode {
27 fn encoded_len(&self) -> Result<Length>;
29
30 fn encode(&self, encoder: &mut impl Writer) -> Result<()>;
32
33 fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
36 let mut writer = SliceWriter::new(buf);
37 self.encode(&mut writer)?;
38 writer.finish()
39 }
40
41 #[cfg(feature = "alloc")]
44 fn encode_to_vec(&self, buf: &mut Vec<u8>) -> Result<Length> {
45 let expected_len = usize::try_from(self.encoded_len()?)?;
46 let initial_len = buf.len();
47 buf.resize(initial_len + expected_len, 0u8);
48
49 let buf_slice = &mut buf[initial_len..];
50 let actual_len = self.encode_to_slice(buf_slice)?.len();
51
52 if expected_len != actual_len {
53 return Err(ErrorKind::Incomplete {
54 expected_len: expected_len.try_into()?,
55 actual_len: actual_len.try_into()?,
56 }
57 .into());
58 }
59
60 actual_len.try_into()
61 }
62
63 #[cfg(feature = "alloc")]
65 fn to_der(&self) -> Result<Vec<u8>> {
66 let mut buf = Vec::new();
67 self.encode_to_vec(&mut buf)?;
68 Ok(buf)
69 }
70}
71
72impl<T> Encode for T
73where
74 T: EncodeValue + Tagged + ?Sized,
75{
76 fn encoded_len(&self) -> Result<Length> {
78 self.value_len().and_then(|len| len.for_tlv(self.tag()))
79 }
80
81 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
83 self.header()?.encode(writer)?;
84 self.encode_value(writer)
85 }
86}
87
88impl<T> Encode for PhantomData<T>
91where
92 T: ?Sized,
93{
94 fn encoded_len(&self) -> Result<Length> {
95 Ok(Length::ZERO)
96 }
97
98 fn encode(&self, _writer: &mut impl Writer) -> Result<()> {
99 Ok(())
100 }
101}
102
103#[cfg(feature = "pem")]
108#[diagnostic::on_unimplemented(
109 note = "`EncodePem` is auto-impl'd for types which impl both `Encode` and `PemLabel`"
110)]
111pub trait EncodePem: Encode + PemLabel {
112 fn to_pem(&self, line_ending: LineEnding) -> Result<String>;
114}
115
116#[cfg(feature = "pem")]
117impl<T> EncodePem for T
118where
119 T: Encode + PemLabel + ?Sized,
120{
121 fn to_pem(&self, line_ending: LineEnding) -> Result<String> {
122 let der_len = usize::try_from(self.encoded_len()?)?;
123 let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, der_len)?;
124
125 let mut buf = vec![0u8; pem_len];
126 let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?;
127 self.encode(&mut writer)?;
128
129 let actual_len = writer.finish()?;
130 buf.truncate(actual_len);
131 Ok(String::from_utf8(buf)?)
132 }
133}
134
135pub trait EncodeValue {
138 fn header(&self) -> Result<Header>
140 where
141 Self: Tagged,
142 {
143 Ok(Header::new(self.tag(), self.value_len()?))
144 }
145
146 fn value_len(&self) -> Result<Length>;
149
150 fn encode_value(&self, encoder: &mut impl Writer) -> Result<()>;
153}
154
155#[cfg(feature = "alloc")]
156impl<T> EncodeValue for Box<T>
157where
158 T: EncodeValue,
159{
160 fn value_len(&self) -> Result<Length> {
161 T::value_len(self)
162 }
163 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
164 T::encode_value(self, writer)
165 }
166}
167
168pub(crate) fn encode_value_to_slice<'a, T>(buf: &'a mut [u8], value: &T) -> Result<&'a [u8]>
170where
171 T: EncodeValue,
172{
173 let mut encoder = SliceWriter::new(buf);
174 value.encode_value(&mut encoder)?;
175 encoder.finish()
176}