commonware_codec/types/
btree_set.rs1extern crate alloc;
7
8use crate::{
9 codec::{EncodeSize, Read, Write},
10 error::Error,
11 RangeCfg,
12};
13use alloc::collections::BTreeSet;
14use bytes::{Buf, BufMut};
15use core::cmp::Ordering;
16
17const BTREESET_TYPE: &str = "BTreeSet";
18
19fn read_ordered_set<K, F>(
21 buf: &mut impl Buf,
22 len: usize,
23 cfg: &K::Cfg,
24 mut insert: F,
25 set_type: &'static str,
26) -> Result<(), Error>
27where
28 K: Read + Ord,
29 F: FnMut(K) -> bool,
30{
31 let mut last: Option<K> = None;
32 for _ in 0..len {
33 let item = K::read_cfg(buf, cfg)?;
35
36 if let Some(ref last) = last {
38 match item.cmp(last) {
39 Ordering::Equal => return Err(Error::Invalid(set_type, "Duplicate item")),
40 Ordering::Less => return Err(Error::Invalid(set_type, "Items must ascend")),
41 _ => {}
42 }
43 }
44
45 if let Some(last) = last.take() {
47 insert(last);
48 }
49 last = Some(item);
50 }
51
52 if let Some(last) = last {
54 insert(last);
55 }
56
57 Ok(())
58}
59
60impl<K: Ord + Eq + Write> Write for BTreeSet<K> {
63 fn write(&self, buf: &mut impl BufMut) {
64 self.len().write(buf);
65
66 for item in self {
68 item.write(buf);
69 }
70 }
71}
72
73impl<K: Ord + Eq + EncodeSize> EncodeSize for BTreeSet<K> {
74 fn encode_size(&self) -> usize {
75 let mut size = self.len().encode_size();
76 for item in self {
77 size += item.encode_size();
78 }
79 size
80 }
81}
82
83impl<K: Read + Clone + Ord + Eq> Read for BTreeSet<K> {
84 type Cfg = (RangeCfg, K::Cfg);
85
86 fn read_cfg(buf: &mut impl Buf, (range, cfg): &Self::Cfg) -> Result<Self, Error> {
87 let len = usize::read_cfg(buf, range)?;
89 let mut set = BTreeSet::new();
90
91 read_ordered_set(buf, len, cfg, |item| set.insert(item), BTREESET_TYPE)?;
93
94 Ok(set)
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::{
102 codec::{Decode, Encode},
103 FixedSize,
104 };
105 use bytes::{Bytes, BytesMut};
106 use core::fmt::Debug;
107
108 fn round_trip_btree<K>(set: &BTreeSet<K>, range_cfg: RangeCfg, item_cfg: K::Cfg)
110 where
111 K: Write + EncodeSize + Read + Clone + Ord + Eq + Debug + PartialEq,
112 BTreeSet<K>: Read<Cfg = (RangeCfg, K::Cfg)>
113 + Decode<Cfg = (RangeCfg, K::Cfg)>
114 + Debug
115 + PartialEq
116 + Write
117 + EncodeSize,
118 {
119 let encoded = set.encode();
120 assert_eq!(set.encode_size(), encoded.len());
121 let config_tuple = (range_cfg, item_cfg);
122 let decoded = BTreeSet::<K>::decode_cfg(encoded, &config_tuple).expect("decode_cfg failed");
123 assert_eq!(set, &decoded);
124 }
125
126 #[test]
127 fn test_empty_btreeset() {
128 let set = BTreeSet::<u32>::new();
129 round_trip_btree(&set, (..).into(), ());
130 assert_eq!(set.encode_size(), 1); let encoded = set.encode();
132 assert_eq!(encoded, Bytes::from_static(&[0]));
133 }
134
135 #[test]
136 fn test_simple_btreeset_u32() {
137 let mut set = BTreeSet::new();
138 set.insert(1u32);
139 set.insert(5u32);
140 set.insert(2u32);
141 round_trip_btree(&set, (..).into(), ());
142 assert_eq!(set.encode_size(), 1 + 3 * u32::SIZE);
143 }
144
145 #[test]
146 fn test_large_btreeset() {
147 let set: BTreeSet<_> = (0..1000u16).collect();
149 round_trip_btree(&set, (1000..=1000).into(), ());
150
151 let set: BTreeSet<_> = (0..1000usize).collect();
153 round_trip_btree(&set, (1000..=1000).into(), (..=1000).into());
154 }
155
156 #[test]
157 fn test_btreeset_decode_length_limit_exceeded() {
158 let mut set = BTreeSet::new();
159 set.insert(1u32);
160 set.insert(5u32);
161 let encoded = set.encode();
162
163 let config_tuple = ((0..=1).into(), ());
164 let result = BTreeSet::<u32>::decode_cfg(encoded, &config_tuple);
165 assert!(matches!(result, Err(Error::InvalidLength(2))));
166 }
167
168 #[test]
169 fn test_btreeset_decode_invalid_item_order() {
170 let mut encoded = BytesMut::new();
171 2usize.write(&mut encoded); 5u32.write(&mut encoded); 2u32.write(&mut encoded); let config_tuple = ((..).into(), ());
176 let result = BTreeSet::<u32>::decode_cfg(encoded, &config_tuple);
177 assert!(matches!(
178 result,
179 Err(Error::Invalid("BTreeSet", "Items must ascend"))
180 ));
181 }
182
183 #[test]
184 fn test_btreeset_decode_duplicate_item() {
185 let mut encoded = BytesMut::new();
186 2usize.write(&mut encoded); 1u32.write(&mut encoded); 1u32.write(&mut encoded); let config_tuple = ((..).into(), ());
191 let result = BTreeSet::<u32>::decode_cfg(encoded, &config_tuple);
192 assert!(matches!(
193 result,
194 Err(Error::Invalid("BTreeSet", "Duplicate item"))
195 ));
196 }
197
198 #[test]
199 fn test_btreeset_deterministic_encoding() {
200 let mut set1 = BTreeSet::new();
201 (0..1000u32).for_each(|i| {
202 set1.insert(i);
203 });
204
205 let mut set2 = BTreeSet::new();
206 (0..1000u32).rev().for_each(|i| {
207 set2.insert(i);
208 });
209
210 assert_eq!(set1.encode(), set2.encode());
211 }
212}