1use crate::{
7 Buf, RangeCfg,
8 codec::{BufsMut, EncodeSize, Read, Write},
9 error::Error,
10 types::read_ordered_set,
11};
12use bytes::BufMut;
13use std::{collections::HashSet, hash::Hash};
14
15const HASHSET_TYPE: &str = "HashSet";
16
17impl<K: Ord + Write, S> Write for HashSet<K, S> {
18 fn write(&self, buf: &mut impl BufMut) {
19 self.len().write(buf);
20
21 let mut items: Vec<_> = self.iter().collect();
23 items.sort_unstable();
24 for item in items {
25 item.write(buf);
26 }
27 }
28
29 fn write_bufs(&self, buf: &mut impl BufsMut) {
30 self.len().write(buf);
31
32 let mut items: Vec<_> = self.iter().collect();
34 items.sort_unstable();
35 for item in items {
36 item.write_bufs(buf);
37 }
38 }
39}
40
41impl<K: EncodeSize, S> EncodeSize for HashSet<K, S> {
42 fn encode_size(&self) -> usize {
43 let mut size = self.len().encode_size();
44
45 for item in self {
47 size += item.encode_size();
48 }
49 size
50 }
51
52 fn encode_inline_size(&self) -> usize {
53 let mut size = self.len().encode_size();
54
55 for item in self {
57 size += item.encode_inline_size();
58 }
59 size
60 }
61}
62
63impl<K: Read + Ord + Hash> Read for HashSet<K> {
64 type Cfg = (RangeCfg<usize>, K::Cfg);
65
66 fn read_cfg(buf: &mut impl Buf, (range, cfg): &Self::Cfg) -> Result<Self, Error> {
67 let len = usize::read_cfg(buf, range)?;
69 let mut set = Self::with_capacity(len.min(buf.remaining()));
70
71 read_ordered_set(buf, len, cfg, |item| set.insert(item), HASHSET_TYPE)?;
73
74 Ok(set)
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::{
82 FixedSize,
83 codec::{Decode, Encode},
84 types::tests::TrackingWriteBuf,
85 };
86 use bytes::{Bytes, BytesMut};
87 use std::{collections::BTreeSet, fmt::Debug};
88
89 fn round_trip_hash<K>(set: &HashSet<K>, range_cfg: RangeCfg<usize>, item_cfg: K::Cfg)
91 where
92 K: Write + EncodeSize + Read + Ord + Hash + Debug,
93 HashSet<K>: Read<Cfg = (RangeCfg<usize>, K::Cfg)>
94 + Decode<Cfg = (RangeCfg<usize>, K::Cfg)>
95 + Debug
96 + PartialEq
97 + Write
98 + EncodeSize,
99 {
100 let encoded = set.encode();
101 assert_eq!(set.encode_size(), encoded.len());
102 let config_tuple = (range_cfg, item_cfg);
103 let decoded = HashSet::<K>::decode_cfg(encoded, &config_tuple).expect("decode_cfg failed");
104 assert_eq!(set, &decoded);
105 }
106
107 #[test]
110 fn test_empty_hashset() {
111 let set = HashSet::<u32>::new();
112 round_trip_hash(&set, (..).into(), ());
113 assert_eq!(set.encode_size(), 1); let encoded = set.encode();
115 assert_eq!(encoded, Bytes::from_static(&[0]));
116 }
117
118 #[test]
119 fn test_simple_hashset_u32() {
120 let mut set = HashSet::new();
121 set.insert(1u32);
122 set.insert(5u32);
123 set.insert(2u32);
124 round_trip_hash(&set, (..).into(), ());
125 assert_eq!(set.encode_size(), 1 + 3 * u32::SIZE);
127 let mut expected = BytesMut::new();
129 3usize.write(&mut expected); 1u32.write(&mut expected);
131 2u32.write(&mut expected);
132 5u32.write(&mut expected);
133 assert_eq!(set.encode(), expected.freeze());
134 }
135
136 #[test]
137 fn test_large_hashset() {
138 let set: HashSet<_> = (0..1000u16).collect();
140 round_trip_hash(&set, (1000..=1000).into(), ());
141
142 let set: HashSet<_> = (0..1000usize).collect();
144 round_trip_hash(&set, (1000..=1000).into(), (..=1000).into());
145 }
146
147 #[test]
148 fn test_hashset_with_variable_items() {
149 let mut set = HashSet::new();
150 set.insert(Bytes::from_static(b"apple"));
151 set.insert(Bytes::from_static(b"banana"));
152 set.insert(Bytes::from_static(b"cherry"));
153
154 let set_range = 0..=10;
155 let item_range = ..=10; round_trip_hash(&set, set_range.into(), item_range.into());
158 }
159
160 #[test]
161 fn test_hashset_decode_length_limit_exceeded() {
162 let mut set = HashSet::new();
163 set.insert(1u32);
164 set.insert(5u32);
165
166 let encoded = set.encode();
167 let config_tuple = ((0..=1).into(), ());
168
169 let result = HashSet::<u32>::decode_cfg(encoded, &config_tuple);
170 assert!(matches!(result, Err(Error::InvalidLength(2))));
171 }
172
173 #[test]
174 fn test_hashset_decode_item_length_limit_exceeded() {
175 let mut set = HashSet::new();
176 set.insert(Bytes::from_static(b"longitem")); let set_range = 0..=10;
179 let restrictive_item_range = ..=5; let encoded = set.encode();
182 let config_tuple = (set_range.into(), restrictive_item_range.into());
183 let result = HashSet::<Bytes>::decode_cfg(encoded, &config_tuple);
184
185 assert!(matches!(result, Err(Error::InvalidLength(8))));
186 }
187
188 #[test]
189 fn test_hashset_decode_invalid_item_order() {
190 let mut encoded = BytesMut::new();
191 2usize.write(&mut encoded); 5u32.write(&mut encoded); 2u32.write(&mut encoded); let config_tuple = ((..).into(), ());
196
197 let result = HashSet::<u32>::decode_cfg(encoded, &config_tuple);
198 assert!(matches!(
199 result,
200 Err(Error::Invalid("HashSet", "Items must ascend"))
201 ));
202 }
203
204 #[test]
205 fn test_hashset_decode_duplicate_item() {
206 let mut encoded = BytesMut::new();
207 2usize.write(&mut encoded); 1u32.write(&mut encoded); 1u32.write(&mut encoded); let config_tuple = ((..).into(), ());
212 let result = HashSet::<u32>::decode_cfg(encoded, &config_tuple);
213 assert!(matches!(
214 result,
215 Err(Error::Invalid("HashSet", "Duplicate item"))
216 ));
217 }
218
219 #[test]
220 fn test_hashset_decode_end_of_buffer() {
221 let mut set = HashSet::new();
222 set.insert(1u32);
223 set.insert(5u32);
224
225 let mut encoded = set.encode(); encoded.truncate(set.encode_size() - 2); let config_tuple = ((..).into(), ());
229 let result = HashSet::<u32>::decode_cfg(encoded, &config_tuple);
230 assert!(matches!(result, Err(Error::EndOfBuffer)));
231 }
232
233 #[test]
234 fn test_hashset_decode_extra_data() {
235 let mut set = HashSet::new();
236 set.insert(1u32);
237
238 let mut encoded = set.encode_mut();
239 encoded.put_u8(0xFF); let config_tuple = ((..).into(), ()); let result = HashSet::<u32>::decode_cfg(encoded.clone(), &config_tuple);
244 assert!(matches!(result, Err(Error::ExtraData(1))));
245
246 let read_result = HashSet::<u32>::read_cfg(&mut encoded.clone(), &config_tuple);
248 assert!(read_result.is_ok());
249 let decoded_set = read_result.unwrap();
250 assert_eq!(decoded_set.len(), 1);
251 assert!(decoded_set.contains(&1u32));
252 }
253
254 #[test]
255 fn test_hashset_deterministic_encoding() {
256 let mut set1 = HashSet::new();
257 (0..1000u32).for_each(|i| {
258 set1.insert(i);
259 });
260
261 let mut set2 = HashSet::new();
262 (0..1000u32).rev().for_each(|i| {
263 set2.insert(i);
264 });
265
266 assert_eq!(set1.encode(), set2.encode());
267 }
268
269 #[test]
270 fn test_hashset_encoding_matches_ordered_set() {
271 for len in [0, 1, 20, 128, 1024] {
273 let ordered: BTreeSet<_> = (0..len)
274 .map(|key: u32| Bytes::copy_from_slice(&key.to_le_bytes()))
275 .collect();
276 let expected = ordered.encode();
277
278 for reverse in [false, true] {
280 let mut entries: Vec<_> = ordered.iter().cloned().collect();
281 if reverse {
282 entries.reverse();
283 }
284 let set: HashSet<_> = entries.into_iter().collect();
285 assert_eq!(set.encode(), expected);
286
287 let mut buf = TrackingWriteBuf::new();
289 set.write_bufs(&mut buf);
290 assert_eq!(buf.freeze(), expected);
291 }
292 }
293 }
294
295 #[test]
296 fn test_hashset_conformity() {
297 let set1 = HashSet::<u8>::new();
299 let mut expected1 = BytesMut::new();
300 0usize.write(&mut expected1); assert_eq!(set1.encode(), expected1.freeze());
302 assert_eq!(set1.encode_size(), 1);
303
304 let mut set2 = HashSet::<u8>::new();
307 set2.insert(5u8);
308 set2.insert(1u8);
309 set2.insert(2u8);
310
311 let mut expected2 = BytesMut::new();
312 3usize.write(&mut expected2); 1u8.write(&mut expected2); 2u8.write(&mut expected2); 5u8.write(&mut expected2); assert_eq!(set2.encode(), expected2.freeze());
317 assert_eq!(set2.encode_size(), 1 + 3);
318
319 let mut set3 = HashSet::<Bytes>::new();
322 set3.insert(Bytes::from_static(b"cherry"));
323 set3.insert(Bytes::from_static(b"apple"));
324 set3.insert(Bytes::from_static(b"banana"));
325
326 let mut expected3 = BytesMut::new();
327 3usize.write(&mut expected3); Bytes::from_static(b"apple").write(&mut expected3);
329 Bytes::from_static(b"banana").write(&mut expected3);
330 Bytes::from_static(b"cherry").write(&mut expected3);
331 assert_eq!(set3.encode(), expected3.freeze());
332 let expected_size = 1usize.encode_size()
333 + Bytes::from_static(b"apple").encode_size()
334 + Bytes::from_static(b"banana").encode_size()
335 + Bytes::from_static(b"cherry").encode_size();
336 assert_eq!(set3.encode_size(), expected_size);
337 }
338
339 #[test]
340 fn test_hashset_malicious_allocation() {
341 let mut malicious_buf = BytesMut::new();
345 (u32::MAX as usize).write(&mut malicious_buf);
346 1u32.write(&mut malicious_buf);
347
348 let result = HashSet::<u32>::decode_cfg(malicious_buf.freeze(), &((..).into(), ()));
349 assert!(matches!(result, Err(Error::EndOfBuffer)));
350 }
351
352 #[cfg(feature = "arbitrary")]
353 mod conformance {
354 use super::*;
355 use crate::conformance::CodecConformance;
356
357 commonware_conformance::conformance_tests! {
358 CodecConformance<HashSet<u32>>
359 }
360 }
361}