1 //! Ordering trait.
2 
3 use crate::{EncodeValue, Result, Tagged};
4 use core::{cmp::Ordering, marker::PhantomData};
5 
6 /// DER ordering trait.
7 ///
8 /// Compares the ordering of two values based on their ASN.1 DER
9 /// serializations.
10 ///
11 /// This is used by the DER encoding for `SET OF` in order to establish an
12 /// ordering for the elements of sets.
13 pub trait DerOrd {
14     /// Return an [`Ordering`] between `self` and `other` when serialized as
15     /// ASN.1 DER.
der_cmp(&self, other: &Self) -> Result<Ordering>16     fn der_cmp(&self, other: &Self) -> Result<Ordering>;
17 }
18 
19 /// DER value ordering trait.
20 ///
21 /// Compares the ordering of the value portion of TLV-encoded DER productions.
22 pub trait ValueOrd {
23     /// Return an [`Ordering`] between value portion of TLV-encoded `self` and
24     /// `other` when serialized as ASN.1 DER.
value_cmp(&self, other: &Self) -> Result<Ordering>25     fn value_cmp(&self, other: &Self) -> Result<Ordering>;
26 }
27 
28 impl<T> DerOrd for T
29 where
30     T: EncodeValue + ValueOrd + Tagged,
31 {
der_cmp(&self, other: &Self) -> Result<Ordering>32     fn der_cmp(&self, other: &Self) -> Result<Ordering> {
33         match self.header()?.der_cmp(&other.header()?)? {
34             Ordering::Equal => self.value_cmp(other),
35             ordering => Ok(ordering),
36         }
37     }
38 }
39 
40 /// Marker trait for types whose `Ord` impl can be used as `ValueOrd`.
41 ///
42 /// This means the `Ord` impl will sort values in the same order as their DER
43 /// encodings.
44 pub trait OrdIsValueOrd: Ord {}
45 
46 impl<T> ValueOrd for T
47 where
48     T: OrdIsValueOrd,
49 {
value_cmp(&self, other: &Self) -> Result<Ordering>50     fn value_cmp(&self, other: &Self) -> Result<Ordering> {
51         Ok(self.cmp(other))
52     }
53 }
54 
55 /// Compare the order of two iterators using [`DerCmp`] on the values.
iter_cmp<'a, I, T: 'a>(a: I, b: I) -> Result<Ordering> where I: Iterator<Item = &'a T> + ExactSizeIterator, T: DerOrd,56 pub(crate) fn iter_cmp<'a, I, T: 'a>(a: I, b: I) -> Result<Ordering>
57 where
58     I: Iterator<Item = &'a T> + ExactSizeIterator,
59     T: DerOrd,
60 {
61     let length_ord = a.len().cmp(&b.len());
62 
63     for (value1, value2) in a.zip(b) {
64         match value1.der_cmp(value2)? {
65             Ordering::Equal => (),
66             other => return Ok(other),
67         }
68     }
69 
70     Ok(length_ord)
71 }
72 
73 /// Provide a no-op implementation for PhantomData
74 impl<T> ValueOrd for PhantomData<T> {
value_cmp(&self, _other: &Self) -> Result<Ordering>75     fn value_cmp(&self, _other: &Self) -> Result<Ordering> {
76         Ok(Ordering::Equal)
77     }
78 }
79 
80 /// Provide a no-op implementation for PhantomData
81 impl<T> DerOrd for PhantomData<T> {
der_cmp(&self, _other: &Self) -> Result<Ordering>82     fn der_cmp(&self, _other: &Self) -> Result<Ordering> {
83         Ok(Ordering::Equal)
84     }
85 }
86