| 1 | // SPDX-License-Identifier: Apache-2.0 |
| 2 | |
| 3 | use crate::value::Value; |
| 4 | use alloc::vec::Vec; |
| 5 | use core::cmp::Ordering; |
| 6 | use serde::{de, ser}; |
| 7 | |
| 8 | /// Manually serialize values to compare them. |
| 9 | fn serialized_canonical_cmp(v1: &Value, v2: &Value) -> Ordering { |
| 10 | // There is an optimization to be done here, but it would take a lot more code |
| 11 | // and using mixing keys, Arrays or Maps as CanonicalValue is probably not the |
| 12 | // best use of this type as it is meant mainly to be used as keys. |
| 13 | |
| 14 | let mut bytes1 = Vec::new(); |
| 15 | let _ = crate::ser::into_writer(v1, &mut bytes1); |
| 16 | let mut bytes2 = Vec::new(); |
| 17 | let _ = crate::ser::into_writer(v2, &mut bytes2); |
| 18 | |
| 19 | match bytes1.len().cmp(&bytes2.len()) { |
| 20 | Ordering::Equal => bytes1.cmp(&bytes2), |
| 21 | x => x, |
| 22 | } |
| 23 | } |
| 24 | |
| 25 | /// Compares two values uses canonical comparison, as defined in both |
| 26 | /// RFC 7049 Section 3.9 (regarding key sorting) and RFC 8949 4.2.3 (as errata). |
| 27 | /// |
| 28 | /// In short, the comparison follow the following rules: |
| 29 | /// - If two keys have different lengths, the shorter one sorts earlier; |
| 30 | /// - If two keys have the same length, the one with the lower value in |
| 31 | /// (byte-wise) lexical order sorts earlier. |
| 32 | /// |
| 33 | /// This specific comparison allows Maps and sorting that respect these two rules. |
| 34 | pub fn cmp_value(v1: &Value, v2: &Value) -> Ordering { |
| 35 | use Value::*; |
| 36 | |
| 37 | match (v1, v2) { |
| 38 | (Integer(i), Integer(o)) => { |
| 39 | // Because of the first rule above, two numbers might be in a different |
| 40 | // order than regular i128 comparison. For example, 10 < -1 in |
| 41 | // canonical ordering, since 10 serializes to `0x0a` and -1 to `0x20`, |
| 42 | // and -1 < -1000 because of their lengths. |
| 43 | i.canonical_cmp(o) |
| 44 | } |
| 45 | (Text(s), Text(o)) => match s.len().cmp(&o.len()) { |
| 46 | Ordering::Equal => s.cmp(o), |
| 47 | x => x, |
| 48 | }, |
| 49 | (Bool(s), Bool(o)) => s.cmp(o), |
| 50 | (Null, Null) => Ordering::Equal, |
| 51 | (Tag(t, v), Tag(ot, ov)) => match Value::from(*t).partial_cmp(&Value::from(*ot)) { |
| 52 | Some(Ordering::Equal) | None => match v.partial_cmp(ov) { |
| 53 | Some(x) => x, |
| 54 | None => serialized_canonical_cmp(v1, v2), |
| 55 | }, |
| 56 | Some(x) => x, |
| 57 | }, |
| 58 | (_, _) => serialized_canonical_cmp(v1, v2), |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | /// A CBOR Value that impl Ord and Eq to allow sorting of values as defined in both |
| 63 | /// RFC 7049 Section 3.9 (regarding key sorting) and RFC 8949 4.2.3 (as errata). |
| 64 | /// |
| 65 | /// Since a regular [Value] can be |
| 66 | #[derive(Clone, Debug)] |
| 67 | pub struct CanonicalValue(Value); |
| 68 | |
| 69 | impl PartialEq for CanonicalValue { |
| 70 | fn eq(&self, other: &Self) -> bool { |
| 71 | self.cmp(other) == Ordering::Equal |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | impl Eq for CanonicalValue {} |
| 76 | |
| 77 | impl From<Value> for CanonicalValue { |
| 78 | fn from(v: Value) -> Self { |
| 79 | Self(v) |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | impl From<CanonicalValue> for Value { |
| 84 | fn from(v: CanonicalValue) -> Self { |
| 85 | v.0 |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | impl ser::Serialize for CanonicalValue { |
| 90 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 91 | where |
| 92 | S: ser::Serializer, |
| 93 | { |
| 94 | self.0.serialize(serializer) |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | impl<'de> de::Deserialize<'de> for CanonicalValue { |
| 99 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 100 | where |
| 101 | D: de::Deserializer<'de>, |
| 102 | { |
| 103 | Value::deserialize(deserializer).map(Into::into) |
| 104 | } |
| 105 | |
| 106 | fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error> |
| 107 | where |
| 108 | D: de::Deserializer<'de>, |
| 109 | { |
| 110 | Value::deserialize_in_place(deserializer, &mut place.0) |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | impl Ord for CanonicalValue { |
| 115 | fn cmp(&self, other: &Self) -> Ordering { |
| 116 | cmp_value(&self.0, &other.0) |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | impl PartialOrd for CanonicalValue { |
| 121 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
| 122 | Some(cmp_value(&self.0, &other.0)) |
| 123 | } |
| 124 | } |
| 125 | |