//! Trait definition for [`Encode`]. use crate::{Header, Length, Result, SliceWriter, Tagged, Writer}; use core::marker::PhantomData; #[cfg(feature = "alloc")] use {alloc::boxed::Box, alloc::vec::Vec, core::iter}; #[cfg(feature = "pem")] use { crate::PemWriter, alloc::string::String, pem_rfc7468::{self as pem, LineEnding, PemLabel}, }; #[cfg(any(feature = "alloc", feature = "pem"))] use crate::ErrorKind; #[cfg(doc)] use crate::Tag; /// Encoding trait. pub trait Encode { /// Compute the length of this value in bytes when encoded as ASN.1 DER. fn encoded_len(&self) -> Result; /// Encode this value as ASN.1 DER using the provided [`Writer`]. fn encode(&self, encoder: &mut impl Writer) -> Result<()>; /// Encode this value to the provided byte slice, returning a sub-slice /// containing the encoded message. fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> { let mut writer = SliceWriter::new(buf); self.encode(&mut writer)?; writer.finish() } /// Encode this message as ASN.1 DER, appending it to the provided /// byte vector. #[cfg(feature = "alloc")] fn encode_to_vec(&self, buf: &mut Vec) -> Result { let expected_len = usize::try_from(self.encoded_len()?)?; buf.reserve(expected_len); buf.extend(iter::repeat(0).take(expected_len)); let mut writer = SliceWriter::new(buf); self.encode(&mut writer)?; let actual_len = writer.finish()?.len(); if expected_len != actual_len { return Err(ErrorKind::Incomplete { expected_len: expected_len.try_into()?, actual_len: actual_len.try_into()?, } .into()); } actual_len.try_into() } /// Encode this type as DER, returning a byte vector. #[cfg(feature = "alloc")] fn to_der(&self) -> Result> { let mut buf = Vec::new(); self.encode_to_vec(&mut buf)?; Ok(buf) } } impl Encode for T where T: EncodeValue + Tagged, { /// Compute the length of this value in bytes when encoded as ASN.1 DER. fn encoded_len(&self) -> Result { self.value_len().and_then(|len| len.for_tlv()) } /// Encode this value as ASN.1 DER using the provided [`Writer`]. fn encode(&self, writer: &mut impl Writer) -> Result<()> { self.header()?.encode(writer)?; self.encode_value(writer) } } /// Dummy implementation for [`PhantomData`] which allows deriving /// implementations on structs with phantom fields. impl Encode for PhantomData where T: ?Sized, { fn encoded_len(&self) -> Result { Ok(Length::ZERO) } fn encode(&self, _writer: &mut impl Writer) -> Result<()> { Ok(()) } } /// PEM encoding trait. /// /// This trait is automatically impl'd for any type which impls both /// [`Encode`] and [`PemLabel`]. #[cfg(feature = "pem")] pub trait EncodePem: Encode + PemLabel { /// Try to encode this type as PEM. fn to_pem(&self, line_ending: LineEnding) -> Result; } #[cfg(feature = "pem")] impl EncodePem for T { fn to_pem(&self, line_ending: LineEnding) -> Result { let der_len = usize::try_from(self.encoded_len()?)?; let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, der_len)?; let mut buf = vec![0u8; pem_len]; let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?; self.encode(&mut writer)?; let actual_len = writer.finish()?; buf.truncate(actual_len); Ok(String::from_utf8(buf)?) } } /// Encode the value part of a Tag-Length-Value encoded field, sans the [`Tag`] /// and [`Length`]. pub trait EncodeValue { /// Get the [`Header`] used to encode this value. fn header(&self) -> Result
where Self: Tagged, { Header::new(self.tag(), self.value_len()?) } /// Compute the length of this value (sans [`Tag`]+[`Length`] header) when /// encoded as ASN.1 DER. fn value_len(&self) -> Result; /// Encode value (sans [`Tag`]+[`Length`] header) as ASN.1 DER using the /// provided [`Writer`]. fn encode_value(&self, encoder: &mut impl Writer) -> Result<()>; } #[cfg(feature = "alloc")] impl EncodeValue for Box where T: EncodeValue, { fn value_len(&self) -> Result { T::value_len(self) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { T::encode_value(self, writer) } }