1extern crate alloc;
7
8use crate::{
9 codec::{EncodeSize, Read, Write},
10 error::Error,
11 types::read_ordered_map,
12 RangeCfg,
13};
14use alloc::collections::BTreeMap;
15use bytes::{Buf, BufMut};
16
17const BTREEMAP_TYPE: &str = "BTreeMap";
18
19impl<K: Ord + Eq + Write, V: Write> Write for BTreeMap<K, V> {
22 fn write(&self, buf: &mut impl BufMut) {
23 self.len().write(buf);
24
25 for (k, v) in self {
27 k.write(buf);
28 v.write(buf);
29 }
30 }
31}
32
33impl<K: Ord + Eq + EncodeSize, V: EncodeSize> EncodeSize for BTreeMap<K, V> {
34 fn encode_size(&self) -> usize {
35 let mut size = self.len().encode_size();
37
38 for (k, v) in self {
40 size += k.encode_size();
41 size += v.encode_size();
42 }
43 size
44 }
45}
46
47impl<K: Read + Clone + Ord + Eq, V: Read + Clone> Read for BTreeMap<K, V> {
48 type Cfg = (RangeCfg<usize>, (K::Cfg, V::Cfg));
49
50 fn read_cfg(buf: &mut impl Buf, (range, (k_cfg, v_cfg)): &Self::Cfg) -> Result<Self, Error> {
51 let len = usize::read_cfg(buf, range)?;
53 let mut map = Self::new();
54
55 read_ordered_map(
57 buf,
58 len,
59 k_cfg,
60 v_cfg,
61 |k, v| map.insert(k, v),
62 BTREEMAP_TYPE,
63 )?;
64
65 Ok(map)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use crate::{Decode, Encode, FixedSize};
73 use bytes::{Bytes, BytesMut};
74 use core::fmt::Debug;
75
76 fn round_trip_btree<K, V, KCfg, VCfg>(
78 map: &BTreeMap<K, V>,
79 range_cfg: RangeCfg<usize>,
80 k_cfg: KCfg,
81 v_cfg: VCfg,
82 ) where
83 K: Write + EncodeSize + Read<Cfg = KCfg> + Clone + Ord + Eq + PartialEq + Debug,
84 V: Write + EncodeSize + Read<Cfg = VCfg> + Clone + PartialEq + Debug,
85 BTreeMap<K, V>: Read<Cfg = (RangeCfg<usize>, (K::Cfg, V::Cfg))>
86 + Decode<Cfg = (RangeCfg<usize>, (K::Cfg, V::Cfg))>
87 + PartialEq
88 + Write
89 + EncodeSize,
90 {
91 let encoded = map.encode();
92 assert_eq!(encoded.len(), map.encode_size());
93 let config_tuple = (range_cfg, (k_cfg, v_cfg));
94 let decoded = BTreeMap::<K, V>::decode_cfg(encoded, &config_tuple)
95 .expect("decode_cfg failed for BTreeMap");
96 assert_eq!(map, &decoded);
97 }
98
99 #[test]
100 fn test_empty_btreemap() {
101 let map = BTreeMap::<u32, u64>::new();
102 round_trip_btree(&map, (..).into(), (), ());
103 assert_eq!(map.encode_size(), 1); let encoded = map.encode();
105 assert_eq!(encoded, Bytes::from_static(&[0]));
106 }
107
108 #[test]
109 fn test_simple_btreemap_u32_u64() {
110 let mut map = BTreeMap::new();
111 map.insert(1u32, 100u64);
112 map.insert(5u32, 500u64);
113 map.insert(2u32, 200u64);
114 round_trip_btree(&map, (..).into(), (), ());
115 assert_eq!(map.encode_size(), 1 + 3 * (u32::SIZE + u64::SIZE));
116 let mut expected = BytesMut::new();
118 3usize.write(&mut expected); 1u32.write(&mut expected);
120 100u64.write(&mut expected);
121 2u32.write(&mut expected);
122 200u64.write(&mut expected);
123 5u32.write(&mut expected);
124 500u64.write(&mut expected);
125 assert_eq!(map.encode(), expected.freeze());
126 }
127
128 #[test]
129 fn test_large_btreemap() {
130 let mut map = BTreeMap::new();
132 for i in 0..1000 {
133 map.insert(i as u16, i as u64 * 2);
134 }
135 round_trip_btree(&map, (0..=1000).into(), (), ());
136
137 let mut map = BTreeMap::new();
139 for i in 0..1000usize {
140 map.insert(i, 1000usize + i);
141 }
142 round_trip_btree(
143 &map,
144 (0..=1000).into(),
145 (..=1000).into(),
146 (1000..=2000).into(),
147 );
148 }
149
150 #[test]
151 fn test_btreemap_decode_length_limit_exceeded() {
152 let mut map = BTreeMap::new();
153 map.insert(1u32, 100u64);
154 map.insert(5u32, 500u64);
155
156 let encoded = map.encode();
157 let config_tuple = ((0..=1).into(), ((), ()));
158
159 let result = BTreeMap::<u32, u64>::decode_cfg(encoded, &config_tuple);
160 assert!(matches!(result, Err(Error::InvalidLength(2))));
161 }
162
163 #[test]
164 fn test_btreemap_decode_invalid_key_order() {
165 let mut encoded = BytesMut::new();
166 2usize.write(&mut encoded); 5u32.write(&mut encoded); 500u64.write(&mut encoded); 2u32.write(&mut encoded); 200u64.write(&mut encoded); let range = (..).into();
173 let config_tuple = (range, ((), ()));
174
175 let result = BTreeMap::<u32, u64>::decode_cfg(encoded, &config_tuple);
176 assert!(matches!(
177 result,
178 Err(Error::Invalid("BTreeMap", "Keys must ascend"))
179 ));
180 }
181
182 #[test]
183 fn test_btreemap_decode_duplicate_key() {
184 let mut encoded = BytesMut::new();
185 2usize.write(&mut encoded); 1u32.write(&mut encoded); 100u64.write(&mut encoded); 1u32.write(&mut encoded); 200u64.write(&mut encoded); let range = (..).into();
192 let config_tuple = (range, ((), ()));
193
194 let result = BTreeMap::<u32, u64>::decode_cfg(encoded, &config_tuple);
195 assert!(matches!(
196 result,
197 Err(Error::Invalid("BTreeMap", "Duplicate key"))
198 ));
199 }
200
201 #[test]
202 fn test_btreemap_deterministic_encoding() {
203 let mut map2 = BTreeMap::new();
205 (0..=1000u32).for_each(|i| {
206 map2.insert(i, i * 2);
207 });
208
209 let mut map1 = BTreeMap::new();
211 (0..=1000u32).rev().for_each(|i| {
212 map1.insert(i, i * 2);
213 });
214
215 assert_eq!(map1.encode(), map2.encode());
216 }
217
218 #[cfg(feature = "arbitrary")]
219 mod conformance {
220 use super::*;
221 use crate::conformance::CodecConformance;
222
223 commonware_conformance::conformance_tests! {
224 CodecConformance<BTreeMap<u32, u32>>,
225 }
226 }
227}