//! ASN.1 `SEQUENCE OF` support. use crate::{ arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::cmp::Ordering; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// ASN.1 `SEQUENCE OF` backed by an array. /// /// This type implements an append-only `SEQUENCE OF` type which is stack-based /// and does not depend on `alloc` support. // TODO(tarcieri): use `ArrayVec` when/if it's merged into `core` // See: https://github.com/rust-lang/rfcs/pull/2990 #[derive(Clone, Debug, Eq, PartialEq)] pub struct SequenceOf { inner: ArrayVec, } impl SequenceOf { /// Create a new [`SequenceOf`]. pub fn new() -> Self { Self { inner: ArrayVec::new(), } } /// Add an element to this [`SequenceOf`]. pub fn add(&mut self, element: T) -> Result<()> { self.inner.push(element) } /// Get an element of this [`SequenceOf`]. pub fn get(&self, index: usize) -> Option<&T> { self.inner.get(index) } /// Iterate over the elements in this [`SequenceOf`]. pub fn iter(&self) -> SequenceOfIter<'_, T> { SequenceOfIter { inner: self.inner.iter(), } } /// Is this [`SequenceOf`] empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Number of elements in this [`SequenceOf`]. pub fn len(&self) -> usize { self.inner.len() } } impl Default for SequenceOf { fn default() -> Self { Self::new() } } impl<'a, T, const N: usize> DecodeValue<'a> for SequenceOf where T: Decode<'a>, { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_nested(header.length, |reader| { let mut sequence_of = Self::new(); while !reader.is_finished() { sequence_of.add(T::decode(reader)?)?; } Ok(sequence_of) }) } } impl EncodeValue for SequenceOf where T: Encode, { fn value_len(&self) -> Result { self.iter() .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { for elem in self.iter() { elem.encode(writer)?; } Ok(()) } } impl FixedTag for SequenceOf { const TAG: Tag = Tag::Sequence; } impl ValueOrd for SequenceOf where T: DerOrd, { fn value_cmp(&self, other: &Self) -> Result { iter_cmp(self.iter(), other.iter()) } } /// Iterator over the elements of an [`SequenceOf`]. #[derive(Clone, Debug)] pub struct SequenceOfIter<'a, T> { /// Inner iterator. inner: arrayvec::Iter<'a, T>, } impl<'a, T> Iterator for SequenceOfIter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { self.inner.next() } } impl<'a, T> ExactSizeIterator for SequenceOfIter<'a, T> {} impl<'a, T, const N: usize> DecodeValue<'a> for [T; N] where T: Decode<'a>, { fn decode_value>(reader: &mut R, header: Header) -> Result { let sequence_of = SequenceOf::::decode_value(reader, header)?; // TODO(tarcieri): use `[T; N]::try_map` instead of `expect` when stable if sequence_of.inner.len() == N { Ok(sequence_of .inner .into_array() .map(|elem| elem.expect("arrayvec length mismatch"))) } else { Err(Self::TAG.length_error()) } } } impl EncodeValue for [T; N] where T: Encode, { fn value_len(&self) -> Result { self.iter() .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { for elem in self { elem.encode(writer)?; } Ok(()) } } impl FixedTag for [T; N] { const TAG: Tag = Tag::Sequence; } impl ValueOrd for [T; N] where T: DerOrd, { fn value_cmp(&self, other: &Self) -> Result { iter_cmp(self.iter(), other.iter()) } } #[cfg(feature = "alloc")] impl<'a, T> DecodeValue<'a> for Vec where T: Decode<'a>, { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_nested(header.length, |reader| { let mut sequence_of = Self::new(); while !reader.is_finished() { sequence_of.push(T::decode(reader)?); } Ok(sequence_of) }) } } #[cfg(feature = "alloc")] impl EncodeValue for Vec where T: Encode, { fn value_len(&self) -> Result { self.iter() .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { for elem in self { elem.encode(writer)?; } Ok(()) } } #[cfg(feature = "alloc")] impl FixedTag for Vec { const TAG: Tag = Tag::Sequence; } #[cfg(feature = "alloc")] impl ValueOrd for Vec where T: DerOrd, { fn value_cmp(&self, other: &Self) -> Result { iter_cmp(self.iter(), other.iter()) } }