//! The [`Sequence`] trait simplifies writing decoders/encoders which map ASN.1 //! `SEQUENCE`s to Rust structs. use crate::{ ByteSlice, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; /// ASN.1 `SEQUENCE` trait. /// /// Types which impl this trait receive blanket impls for the [`Decode`], /// [`Encode`], and [`FixedTag`] traits. pub trait Sequence<'a>: Decode<'a> { /// Call the provided function with a slice of [`Encode`] trait objects /// representing the fields of this `SEQUENCE`. /// /// This method uses a callback because structs with fields which aren't /// directly [`Encode`] may need to construct temporary values from /// their fields prior to encoding. fn fields(&self, f: F) -> Result where F: FnOnce(&[&dyn Encode]) -> Result; } impl<'a, M> EncodeValue for M where M: Sequence<'a>, { fn value_len(&self) -> Result { self.fields(|fields| { fields .iter() .try_fold(Length::ZERO, |acc, field| acc + field.encoded_len()?) }) } fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { self.fields(|fields| { for &field in fields { field.encode(writer)?; } Ok(()) }) } } impl<'a, M> FixedTag for M where M: Sequence<'a>, { const TAG: Tag = Tag::Sequence; } /// The [`SequenceRef`] type provides raw access to the octets which comprise a /// DER-encoded `SEQUENCE`. /// /// This is a zero-copy reference type which borrows from the input data. pub struct SequenceRef<'a> { /// Body of the `SEQUENCE`. body: ByteSlice<'a>, } impl<'a> DecodeValue<'a> for SequenceRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(Self { body: ByteSlice::decode_value(reader, header)?, }) } } impl EncodeValue for SequenceRef<'_> { fn value_len(&self) -> Result { Ok(self.body.len()) } fn encode_value(&self, writer: &mut dyn Writer) -> Result<()> { self.body.encode_value(writer) } } impl<'a> FixedTag for SequenceRef<'a> { const TAG: Tag = Tag::Sequence; }