Skip to main content

ssh_encoding/pem/
encode.rs

1use super::{LineEnding, PemLabel, writer::PemWriter};
2use crate::{Encode, Error};
3use core::str;
4
5#[cfg(feature = "alloc")]
6use {super::LINE_WIDTH, alloc::string::String};
7
8/// Encoding trait for PEM documents.
9///
10/// This is an extension trait which is auto-impl'd for types which impl the [`Encode`] and
11/// [`PemLabel`] traits.
12#[diagnostic::on_unimplemented(
13    note = "Consider adding impls of `Encode` and `PemLabel` to `{Self}`"
14)]
15pub trait EncodePem: Encode + PemLabel {
16    /// Encode this type using the [`Encode`] trait, writing the resulting PEM document into the
17    /// provided `out` buffer.
18    ///
19    /// # Errors
20    /// - Returns [`Error::Pem`] in the event of PEM encoding errors.
21    /// - Propagates errors returned from the [`Encode::encode`] method.
22    fn encode_pem<'o>(&self, line_ending: LineEnding, out: &'o mut [u8]) -> Result<&'o str, Error>;
23
24    /// Encode this type using the [`Encode`] trait, writing the resulting PEM  document to a
25    /// returned [`String`].
26    ///
27    /// # Errors
28    /// Propagates errors returned from [`EncodePem::encode_pem`].
29    #[cfg(feature = "alloc")]
30    fn encode_pem_string(&self, line_ending: LineEnding) -> Result<String, Error>;
31}
32
33impl<T: Encode + PemLabel> EncodePem for T {
34    fn encode_pem<'o>(&self, line_ending: LineEnding, out: &'o mut [u8]) -> Result<&'o str, Error> {
35        let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, out)?;
36        self.encode(&mut writer)?;
37
38        let encoded_len = writer.finish()?;
39        str::from_utf8(&out[..encoded_len]).map_err(Error::from)
40    }
41
42    #[cfg(feature = "alloc")]
43    fn encode_pem_string(&self, line_ending: LineEnding) -> Result<String, Error> {
44        let encoded_len = pem_rfc7468::encapsulated_len_wrapped(
45            Self::PEM_LABEL,
46            LINE_WIDTH,
47            line_ending,
48            self.encoded_len()?,
49        )
50        .map_err(Error::from)?;
51
52        let mut buf = vec![0u8; encoded_len];
53        let actual_len = self.encode_pem(line_ending, &mut buf)?.len();
54        buf.truncate(actual_len);
55        String::from_utf8(buf).map_err(Error::from)
56    }
57}