1use crate::value::Value;
8use std::cmp::Ordering;
9
10#[derive(Clone, Debug, Eq, PartialEq)]
19pub enum MapValueError {
20 EmptyKey {
21 index: usize,
22 },
23 NonScalarKey {
24 index: usize,
25 key: Value,
26 },
27 NonScalarValue {
28 index: usize,
29 value: Value,
30 },
31 DuplicateKey {
32 left_index: usize,
33 right_index: usize,
34 },
35}
36
37impl std::fmt::Display for MapValueError {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 match self {
40 Self::EmptyKey { index } => write!(f, "map key at index {index} must be non-null"),
41 Self::NonScalarKey { index, key } => {
42 write!(f, "map key at index {index} is not scalar: {key:?}")
43 }
44 Self::NonScalarValue { index, value } => {
45 write!(
46 f,
47 "map value at index {index} is not scalar/ref-like: {value:?}"
48 )
49 }
50 Self::DuplicateKey {
51 left_index,
52 right_index,
53 } => write!(
54 f,
55 "map contains duplicate keys at normalized positions {left_index} and {right_index}"
56 ),
57 }
58 }
59}
60
61impl std::error::Error for MapValueError {}
62
63#[derive(Clone, Debug, Eq, PartialEq)]
72pub enum SchemaInvariantError {
73 InvalidMapValue(MapValueError),
74}
75
76impl std::fmt::Display for SchemaInvariantError {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 Self::InvalidMapValue(err) => write!(f, "{err}"),
80 }
81 }
82}
83
84impl std::error::Error for SchemaInvariantError {}
85
86impl From<MapValueError> for SchemaInvariantError {
87 fn from(value: MapValueError) -> Self {
88 Self::InvalidMapValue(value)
89 }
90}
91
92pub fn validate_map_entries(entries: &[(Value, Value)]) -> Result<(), MapValueError> {
94 for (index, (key, _value)) in entries.iter().enumerate() {
95 if matches!(key, Value::Null) {
96 return Err(MapValueError::EmptyKey { index });
97 }
98 if !key.is_scalar() {
99 return Err(MapValueError::NonScalarKey {
100 index,
101 key: key.clone(),
102 });
103 }
104 }
105
106 Ok(())
107}
108
109pub(crate) fn compare_map_entry_keys(left: &(Value, Value), right: &(Value, Value)) -> Ordering {
111 Value::canonical_cmp_key(&left.0, &right.0)
112}
113
114pub(crate) fn sort_map_entries_in_place(entries: &mut [(Value, Value)]) {
116 entries.sort_by(compare_map_entry_keys);
117}
118
119pub(crate) fn map_entries_are_strictly_canonical(entries: &[(Value, Value)]) -> bool {
122 entries.windows(2).all(|pair| {
123 let [left, right] = pair else {
124 return true;
125 };
126
127 compare_map_entry_keys(left, right) == Ordering::Less
128 })
129}
130
131pub fn normalize_map_entries(
133 mut entries: Vec<(Value, Value)>,
134) -> Result<Vec<(Value, Value)>, MapValueError> {
135 validate_map_entries(&entries)?;
136 sort_map_entries_in_place(entries.as_mut_slice());
137
138 for i in 1..entries.len() {
139 let (left_key, _) = &entries[i - 1];
140 let (right_key, _) = &entries[i];
141 if Value::canonical_cmp_key(left_key, right_key) == Ordering::Equal {
142 return Err(MapValueError::DuplicateKey {
143 left_index: i - 1,
144 right_index: i,
145 });
146 }
147 }
148
149 Ok(entries)
150}
151
152impl Value {
153 pub fn validate_map_entries(entries: &[(Self, Self)]) -> Result<(), MapValueError> {
155 validate_map_entries(entries)
156 }
157
158 pub(crate) fn sort_map_entries_in_place(entries: &mut [(Self, Self)]) {
160 sort_map_entries_in_place(entries);
161 }
162
163 pub(crate) fn map_entries_are_strictly_canonical(entries: &[(Self, Self)]) -> bool {
166 map_entries_are_strictly_canonical(entries)
167 }
168
169 pub fn normalize_map_entries(
171 entries: Vec<(Self, Self)>,
172 ) -> Result<Vec<(Self, Self)>, MapValueError> {
173 normalize_map_entries(entries)
174 }
175}