summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/asn1/optional.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/der/src/asn1/optional.rs')
-rw-r--r--vendor/der/src/asn1/optional.rs66
1 files changed, 66 insertions, 0 deletions
diff --git a/vendor/der/src/asn1/optional.rs b/vendor/der/src/asn1/optional.rs
new file mode 100644
index 0000000..ecda4f8
--- /dev/null
+++ b/vendor/der/src/asn1/optional.rs
@@ -0,0 +1,66 @@
+//! ASN.1 `OPTIONAL` as mapped to Rust's `Option` type
+
+use crate::{Choice, Decode, DerOrd, Encode, Length, Reader, Result, Tag, Writer};
+use core::cmp::Ordering;
+
+impl<'a, T> Decode<'a> for Option<T>
+where
+ T: Choice<'a>, // NOTE: all `Decode + Tagged` types receive a blanket `Choice` impl
+{
+ fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Option<T>> {
+ if let Some(byte) = reader.peek_byte() {
+ if T::can_decode(Tag::try_from(byte)?) {
+ return T::decode(reader).map(Some);
+ }
+ }
+
+ Ok(None)
+ }
+}
+
+impl<T> DerOrd for Option<T>
+where
+ T: DerOrd,
+{
+ fn der_cmp(&self, other: &Self) -> Result<Ordering> {
+ match self {
+ Some(a) => match other {
+ Some(b) => a.der_cmp(b),
+ None => Ok(Ordering::Greater),
+ },
+ None => Ok(Ordering::Less),
+ }
+ }
+}
+
+impl<T> Encode for Option<T>
+where
+ T: Encode,
+{
+ fn encoded_len(&self) -> Result<Length> {
+ (&self).encoded_len()
+ }
+
+ fn encode(&self, writer: &mut impl Writer) -> Result<()> {
+ (&self).encode(writer)
+ }
+}
+
+impl<T> Encode for &Option<T>
+where
+ T: Encode,
+{
+ fn encoded_len(&self) -> Result<Length> {
+ match self {
+ Some(encodable) => encodable.encoded_len(),
+ None => Ok(0u8.into()),
+ }
+ }
+
+ fn encode(&self, encoder: &mut impl Writer) -> Result<()> {
+ match self {
+ Some(encodable) => encodable.encode(encoder),
+ None => Ok(()),
+ }
+ }
+}