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    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.
22pub trait ValueOrd {
23    /// Return an [`Ordering`] between value portion of TLV-encoded `self` and
24    /// `other` when serialized as ASN.1 DER.
25    fn value_cmp(&self, other: &Self) -> Result<Ordering>;
26}
27
28impl<T> DerOrd for T
29where
30    T: EncodeValue + ValueOrd + Tagged,
31{
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.
44pub trait OrdIsValueOrd: Ord {}
45
46impl<T> ValueOrd for T
47where
48    T: OrdIsValueOrd,
49{
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.
56pub(crate) fn iter_cmp<'a, I, T: 'a>(a: I, b: I) -> Result<Ordering>
57where
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
74impl<T> ValueOrd for PhantomData<T> {
75    fn value_cmp(&self, _other: &Self) -> Result<Ordering> {
76        Ok(Ordering::Equal)
77    }
78}
79
80/// Provide a no-op implementation for PhantomData
81impl<T> DerOrd for PhantomData<T> {
82    fn der_cmp(&self, _other: &Self) -> Result<Ordering> {
83        Ok(Ordering::Equal)
84    }
85}