1use crate::{BufsMut, EncodeSize, Error, FixedSize, Read, Write};
5use bytes::{Buf, BufMut};
6use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
7
8impl<T: Write + PartialOrd> Write for Range<T> {
9 #[inline]
10 fn write(&self, buf: &mut impl BufMut) {
11 assert!(
12 self.start.partial_cmp(&self.end).is_some_and(|o| o.is_le()),
13 "start must be <= end"
14 );
15 self.start.write(buf);
16 self.end.write(buf);
17 }
18
19 #[inline]
20 fn write_bufs(&self, buf: &mut impl BufsMut) {
21 assert!(
22 self.start.partial_cmp(&self.end).is_some_and(|o| o.is_le()),
23 "start must be <= end"
24 );
25 self.start.write_bufs(buf);
26 self.end.write_bufs(buf);
27 }
28}
29
30impl<T: EncodeSize> EncodeSize for Range<T> {
31 #[inline]
32 fn encode_size(&self) -> usize {
33 self.start.encode_size() + self.end.encode_size()
34 }
35
36 #[inline]
37 fn encode_inline_size(&self) -> usize {
38 self.start.encode_inline_size() + self.end.encode_inline_size()
39 }
40}
41
42impl<T: Read + PartialOrd> Read for Range<T> {
43 type Cfg = T::Cfg;
44
45 #[inline]
46 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
47 let start = T::read_cfg(buf, cfg)?;
48 let end = T::read_cfg(buf, cfg)?;
49 if !start.partial_cmp(&end).is_some_and(|o| o.is_le()) {
50 return Err(Error::Invalid("Range", "start must be <= end"));
51 }
52 Ok(start..end)
53 }
54}
55
56impl<T: Write + PartialOrd> Write for RangeInclusive<T> {
57 #[inline]
58 fn write(&self, buf: &mut impl BufMut) {
59 assert!(
60 self.start()
61 .partial_cmp(self.end())
62 .is_some_and(|o| o.is_le()),
63 "start must be <= end"
64 );
65 self.start().write(buf);
66 self.end().write(buf);
67 }
68
69 #[inline]
70 fn write_bufs(&self, buf: &mut impl BufsMut) {
71 assert!(
72 self.start()
73 .partial_cmp(self.end())
74 .is_some_and(|o| o.is_le()),
75 "start must be <= end"
76 );
77 self.start().write_bufs(buf);
78 self.end().write_bufs(buf);
79 }
80}
81
82impl<T: EncodeSize> EncodeSize for RangeInclusive<T> {
83 #[inline]
84 fn encode_size(&self) -> usize {
85 self.start().encode_size() + self.end().encode_size()
86 }
87
88 #[inline]
89 fn encode_inline_size(&self) -> usize {
90 self.start().encode_inline_size() + self.end().encode_inline_size()
91 }
92}
93
94impl<T: Read + PartialOrd> Read for RangeInclusive<T> {
95 type Cfg = T::Cfg;
96
97 #[inline]
98 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
99 let start = T::read_cfg(buf, cfg)?;
100 let end = T::read_cfg(buf, cfg)?;
101 if !start.partial_cmp(&end).is_some_and(|o| o.is_le()) {
102 return Err(Error::Invalid("RangeInclusive", "start must be <= end"));
103 }
104 Ok(start..=end)
105 }
106}
107
108impl<T: Write> Write for RangeFrom<T> {
109 #[inline]
110 fn write(&self, buf: &mut impl BufMut) {
111 self.start.write(buf);
112 }
113
114 #[inline]
115 fn write_bufs(&self, buf: &mut impl BufsMut) {
116 self.start.write_bufs(buf);
117 }
118}
119
120impl<T: EncodeSize> EncodeSize for RangeFrom<T> {
121 #[inline]
122 fn encode_size(&self) -> usize {
123 self.start.encode_size()
124 }
125
126 #[inline]
127 fn encode_inline_size(&self) -> usize {
128 self.start.encode_inline_size()
129 }
130}
131
132impl<T: Read> Read for RangeFrom<T> {
133 type Cfg = T::Cfg;
134
135 #[inline]
136 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
137 let start = T::read_cfg(buf, cfg)?;
138 Ok(start..)
139 }
140}
141
142impl<T: Write> Write for RangeTo<T> {
143 #[inline]
144 fn write(&self, buf: &mut impl BufMut) {
145 self.end.write(buf);
146 }
147
148 #[inline]
149 fn write_bufs(&self, buf: &mut impl BufsMut) {
150 self.end.write_bufs(buf);
151 }
152}
153
154impl<T: EncodeSize> EncodeSize for RangeTo<T> {
155 #[inline]
156 fn encode_size(&self) -> usize {
157 self.end.encode_size()
158 }
159
160 #[inline]
161 fn encode_inline_size(&self) -> usize {
162 self.end.encode_inline_size()
163 }
164}
165
166impl<T: Read> Read for RangeTo<T> {
167 type Cfg = T::Cfg;
168
169 #[inline]
170 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
171 let end = T::read_cfg(buf, cfg)?;
172 Ok(..end)
173 }
174}
175
176impl<T: Write> Write for RangeToInclusive<T> {
177 #[inline]
178 fn write(&self, buf: &mut impl BufMut) {
179 self.end.write(buf);
180 }
181
182 #[inline]
183 fn write_bufs(&self, buf: &mut impl BufsMut) {
184 self.end.write_bufs(buf);
185 }
186}
187
188impl<T: EncodeSize> EncodeSize for RangeToInclusive<T> {
189 #[inline]
190 fn encode_size(&self) -> usize {
191 self.end.encode_size()
192 }
193
194 #[inline]
195 fn encode_inline_size(&self) -> usize {
196 self.end.encode_inline_size()
197 }
198}
199
200impl<T: Read> Read for RangeToInclusive<T> {
201 type Cfg = T::Cfg;
202
203 #[inline]
204 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
205 let end = T::read_cfg(buf, cfg)?;
206 Ok(..=end)
207 }
208}
209
210impl Write for RangeFull {
211 #[inline]
212 fn write(&self, _buf: &mut impl BufMut) {}
213}
214
215impl FixedSize for RangeFull {
216 const SIZE: usize = 0;
217}
218
219impl Read for RangeFull {
220 type Cfg = ();
221
222 #[inline]
223 fn read_cfg(_buf: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
224 Ok(..)
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use crate::{DecodeExt, Encode, FixedSize};
231 use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
232
233 #[test]
234 fn test_range() {
235 let range: Range<u32> = 10..20;
236 let encoded = range.encode();
237 assert_eq!(encoded.len(), u32::SIZE * 2);
238 let decoded = Range::<u32>::decode(encoded).unwrap();
239 assert_eq!(range, decoded);
240 }
241
242 #[test]
243 fn test_range_inclusive() {
244 let range: RangeInclusive<u32> = 10..=20;
245 let encoded = range.encode();
246 assert_eq!(encoded.len(), u32::SIZE * 2);
247 let decoded = RangeInclusive::<u32>::decode(encoded).unwrap();
248 assert_eq!(range, decoded);
249 }
250
251 #[test]
252 fn test_range_from() {
253 let range: RangeFrom<u32> = 10..;
254 let encoded = range.encode();
255 assert_eq!(encoded.len(), u32::SIZE);
256 let decoded = RangeFrom::<u32>::decode(encoded).unwrap();
257 assert_eq!(range, decoded);
258 }
259
260 #[test]
261 fn test_range_to() {
262 let range: RangeTo<u32> = ..20;
263 let encoded = range.encode();
264 assert_eq!(encoded.len(), u32::SIZE);
265 let decoded = RangeTo::<u32>::decode(encoded).unwrap();
266 assert_eq!(range, decoded);
267 }
268
269 #[test]
270 fn test_range_to_inclusive() {
271 let range: RangeToInclusive<u32> = ..=20;
272 let encoded = range.encode();
273 assert_eq!(encoded.len(), u32::SIZE);
274 let decoded = RangeToInclusive::<u32>::decode(encoded).unwrap();
275 assert_eq!(range, decoded);
276 }
277
278 #[test]
279 fn test_range_full() {
280 let encoded = RangeFull.encode();
281 assert_eq!(encoded.len(), 0);
282 assert_eq!(RangeFull::SIZE, 0);
283 let decoded = RangeFull::decode(encoded).unwrap();
284 assert_eq!(.., decoded);
285 }
286
287 #[test]
288 #[should_panic(expected = "start must be <= end")]
289 fn test_range_encode_invalid() {
290 let range = Range {
291 start: 20u32,
292 end: 10u32,
293 };
294 let _ = range.encode();
295 }
296
297 #[test]
298 fn test_range_decode_invalid() {
299 let mut buf = Vec::new();
301 buf.extend_from_slice(&20u32.to_be_bytes());
302 buf.extend_from_slice(&10u32.to_be_bytes());
303 assert!(matches!(
304 Range::<u32>::decode(bytes::Bytes::from(buf)),
305 Err(crate::Error::Invalid("Range", "start must be <= end"))
306 ));
307 }
308
309 #[test]
310 #[should_panic(expected = "start must be <= end")]
311 fn test_range_inclusive_encode_invalid() {
312 let range = RangeInclusive::new(20u32, 10u32);
313 let _ = range.encode();
314 }
315
316 #[test]
317 fn test_range_inclusive_decode_invalid() {
318 let mut buf = Vec::new();
320 buf.extend_from_slice(&20u32.to_be_bytes());
321 buf.extend_from_slice(&10u32.to_be_bytes());
322 assert!(matches!(
323 RangeInclusive::<u32>::decode(bytes::Bytes::from(buf)),
324 Err(crate::Error::Invalid(
325 "RangeInclusive",
326 "start must be <= end"
327 ))
328 ));
329 }
330
331 #[test]
332 fn test_conformity() {
333 assert_eq!(
334 (0x0102u16..0x0304u16).encode(),
335 &[0x01, 0x02, 0x03, 0x04][..]
336 );
337 assert_eq!(
338 (0x0102u16..=0x0304u16).encode(),
339 &[0x01, 0x02, 0x03, 0x04][..]
340 );
341 assert_eq!((0x0102u16..).encode(), &[0x01, 0x02][..]);
342 assert_eq!((..0x0304u16).encode(), &[0x03, 0x04][..]);
343 assert_eq!((..=0x0304u16).encode(), &[0x03, 0x04][..]);
344 assert_eq!((..).encode(), &[][..]);
345 }
346
347 #[cfg(feature = "arbitrary")]
348 mod conformance {
349 use crate::conformance::CodecConformance;
350 use core::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
351
352 commonware_conformance::conformance_tests! {
353 CodecConformance<Range<u32>>,
354 CodecConformance<Range<u64>>,
355 CodecConformance<RangeInclusive<u32>>,
356 CodecConformance<RangeInclusive<u64>>,
357 CodecConformance<RangeFrom<u32>>,
358 CodecConformance<RangeTo<u32>>,
359 CodecConformance<RangeToInclusive<u32>>,
360 }
361 }
362}