Skip to main content

der/
ord.rs

1//! Ordering trait.
2
3use crate::{EncodeValue, Result, Tagged};
4use 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.
13pub trait DerOrd {
14    /// Return an [`Ordering`] between `self` and `other` when serialized as
15    /// ASN.1 DER.
16    ///
17    /// # Errors
18    /// If an encoding error occurred during the comparison.
19    fn der_cmp(&self, other: &Self) -> Result<Ordering>;
20}
21
22/// DER value ordering trait.
23///
24/// Compares the ordering of the value portion of TLV-encoded DER productions.
25pub trait ValueOrd {
26    /// Return an [`Ordering`] between value portion of TLV-encoded `self` and
27    /// `other` when serialized as ASN.1 DER.
28    ///
29    /// # Errors
30    /// If an encoding error occurred during the comparison.
31    fn value_cmp(&self, other: &Self) -> Result<Ordering>;
32}
33
34impl<T> DerOrd for T
35where
36    T: EncodeValue + ValueOrd + Tagged,
37{
38    fn der_cmp(&self, other: &Self) -> Result<Ordering> {
39        // Written as a match to reduce llvm-ir bloat and faster compile time
40        match (self.header(), other.header()) {
41            (Ok(this), Ok(that)) => {
42                let cmp_result = this.der_cmp(&that);
43                match cmp_result {
44                    Err(err) => Err(err),
45                    Ok(Ordering::Equal) => self.value_cmp(other),
46                    Ok(ordering) => Ok(ordering),
47                }
48            }
49            (Err(err), _) => Err(err),
50            (_, Err(err)) => Err(err),
51        }
52    }
53}
54
55/// Marker trait for types whose `Ord` impl can be used as `ValueOrd`.
56///
57/// This means the `Ord` impl will sort values in the same order as their DER
58/// encodings.
59pub trait OrdIsValueOrd: Ord {}
60
61impl<T> ValueOrd for T
62where
63    T: OrdIsValueOrd,
64{
65    fn value_cmp(&self, other: &Self) -> Result<Ordering> {
66        Ok(self.cmp(other))
67    }
68}
69
70/// Compare the order of two iterators using [`DerCmp`] on the values.
71pub(crate) fn iter_cmp<'a, I, T>(a: I, b: I) -> Result<Ordering>
72where
73    I: Iterator<Item = &'a T> + ExactSizeIterator,
74    T: 'a + DerOrd,
75{
76    let length_ord = a.len().cmp(&b.len());
77
78    for (value1, value2) in a.zip(b) {
79        match value1.der_cmp(value2)? {
80            Ordering::Equal => (),
81            other => return Ok(other),
82        }
83    }
84
85    Ok(length_ord)
86}
87
88/// Provide a no-op implementation for `PhantomData`
89impl<T> ValueOrd for PhantomData<T> {
90    fn value_cmp(&self, _other: &Self) -> Result<Ordering> {
91        Ok(Ordering::Equal)
92    }
93}
94
95/// Provide a no-op implementation for `PhantomData`
96impl<T> DerOrd for PhantomData<T> {
97    fn der_cmp(&self, _other: &Self) -> Result<Ordering> {
98        Ok(Ordering::Equal)
99    }
100}