canadensis_bit_length_set/
lib.rs

1extern crate itertools;
2extern crate num_integer;
3
4mod operator;
5
6use std::cmp::Ordering;
7use std::collections::BTreeSet;
8use std::ops::{RangeToInclusive, Rem};
9use std::{iter, mem};
10
11use crate::operator::Operator;
12
13/// A non-empty set of possible lengths (in bits) for a data type
14///
15/// This is based on the Python version: <https://github.com/OpenCyphal/pydsdl/blob/master/pydsdl/_bit_length_set/_bit_length_set.py>
16#[derive(Debug, Clone)]
17pub struct BitLengthSet {
18    operator: Operator,
19}
20
21impl BitLengthSet {
22    /// Creates a bit length set with one length value in bits
23    pub fn single(length: u64) -> BitLengthSet {
24        let mut values = BTreeSet::new();
25        values.insert(length);
26        BitLengthSet {
27            operator: Operator::Leaf(values),
28        }
29    }
30    /// Creates a bit length set from an iterator of possible length values
31    ///
32    /// If the provided iterator does not yield any elements, this function returns None.
33    pub fn from_lengths<I>(values: I) -> Option<BitLengthSet>
34    where
35        I: IntoIterator<Item = u64>,
36    {
37        let value_set: BTreeSet<u64> = values.into_iter().collect();
38        if value_set.is_empty() {
39            None
40        } else {
41            Some(BitLengthSet {
42                operator: Operator::Leaf(value_set),
43            })
44        }
45    }
46
47    /// Creates a bit length set from a set of possible length values
48    ///
49    /// If the provided set is empty, this function returns None.
50    pub fn from_length_set(values: BTreeSet<u64>) -> Option<BitLengthSet> {
51        if values.is_empty() {
52            None
53        } else {
54            Some(BitLengthSet {
55                operator: Operator::Leaf(values),
56            })
57        }
58    }
59
60    /// Returns the minimum length value in this set
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// # use canadensis_bit_length_set::BitLengthSet;
66    /// let lengths = BitLengthSet::single(37);
67    /// assert_eq!(37, lengths.min_value());
68    /// ```
69    ///
70    /// ```
71    /// # use canadensis_bit_length_set::BitLengthSet;
72    /// let lengths = BitLengthSet::from_lengths([1, 10, 30]).unwrap();
73    /// assert_eq!(1, lengths.min_value());
74    /// ```
75    pub fn min_value(&self) -> u64 {
76        self.operator.min()
77    }
78    /// Returns the maximum length value in this set
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// # use canadensis_bit_length_set::BitLengthSet;
84    /// let lengths = BitLengthSet::single(37);
85    /// assert_eq!(37, lengths.max_value());
86    /// ```
87    ///
88    /// ```
89    /// # use canadensis_bit_length_set::BitLengthSet;
90    /// let lengths = BitLengthSet::from_lengths([1, 10, 30]).unwrap();
91    /// assert_eq!(30, lengths.max_value());
92    /// ```
93    pub fn max_value(&self) -> u64 {
94        self.operator.max()
95    }
96
97    /// Returns true if this set's minimum and maximum values are equal
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// # use canadensis_bit_length_set::BitLengthSet;
103    /// let lengths = BitLengthSet::single(37);
104    /// assert!(lengths.is_fixed_size());
105    /// ```
106    ///
107    /// ```
108    /// # use canadensis_bit_length_set::BitLengthSet;
109    /// let lengths = BitLengthSet::from_lengths([1, 10, 30]).unwrap();
110    /// assert!(!lengths.is_fixed_size());
111    /// ```
112    pub fn is_fixed_size(&self) -> bool {
113        self.min_value() == self.max_value()
114    }
115
116    /// Returns true if all values in this set are aligned to multiples of 8 bits
117    ///
118    /// # Examples
119    ///
120    /// ```
121    /// # use canadensis_bit_length_set::BitLengthSet;
122    /// assert!(BitLengthSet::single(0).is_byte_aligned());
123    /// assert!(BitLengthSet::single(8).is_byte_aligned());
124    /// assert!(BitLengthSet::single(16).is_byte_aligned());
125    ///
126    /// assert!(!BitLengthSet::single(1).is_byte_aligned());
127    /// assert!(!BitLengthSet::single(2).is_byte_aligned());
128    /// assert!(!BitLengthSet::single(4).is_byte_aligned());
129    /// assert!(!BitLengthSet::single(7).is_byte_aligned());
130    ///
131    /// assert!(!BitLengthSet::from_lengths([0, 1, 8, 16, 24]).unwrap().is_byte_aligned());
132    /// assert!(!BitLengthSet::from_lengths([8, 9]).unwrap().is_byte_aligned());
133    ///
134    /// assert!(BitLengthSet::from_lengths([0, 8, 16, 24]).unwrap().is_byte_aligned());
135    /// assert!(BitLengthSet::from_lengths([8, 16]).unwrap().is_byte_aligned());
136    /// ```
137    pub fn is_byte_aligned(&self) -> bool {
138        self.is_aligned(8)
139    }
140
141    /// Returns true if all values in this set are aligned to multiples of the specified number of
142    /// bits
143    ///
144    /// # Examples
145    ///
146    /// ```
147    /// # use canadensis_bit_length_set::BitLengthSet;
148    /// assert!(BitLengthSet::from_lengths([0, 3, 6, 15]).unwrap().is_aligned(3));
149    /// assert!(!BitLengthSet::from_lengths([0, 3, 6, 16]).unwrap().is_aligned(3));
150    ///
151    /// assert!(BitLengthSet::from_lengths([0, 17, 34, 68]).unwrap().is_aligned(17));
152    /// assert!(!BitLengthSet::from_lengths([0, 17, 34, 64]).unwrap().is_aligned(17));
153    /// ```
154    pub fn is_aligned(&self, bit_length: u64) -> bool {
155        let remainder = self % bit_length;
156        remainder.is_fixed_size() && remainder.min_value() == 0
157    }
158
159    /// Expands this bit length set and returns a set with all enclosed values
160    ///
161    /// For some bit length sets, especially when large sets are concatenated, this may be slow.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// # use canadensis_bit_length_set::BitLengthSet;
167    /// # use std::collections::BTreeSet;
168    /// let lengths1 = BitLengthSet::from_lengths([0, 8, 24, 96]).unwrap();
169    /// let lengths2 = BitLengthSet::from_lengths([1, 2, 8]).unwrap();
170    ///
171    /// let union = lengths1.unite([lengths2]);
172    /// let expanded_union = union.expand();
173    ///
174    /// let expected: BTreeSet<u64> = [0, 1, 2, 8, 24, 96].iter().copied().collect();
175    /// assert_eq!(expected, expanded_union);
176    /// ```
177    pub fn expand(&self) -> BTreeSet<u64> {
178        self.operator.expand()
179    }
180
181    /// Converts this bit length set into a new set that aligns up all its values to a multiple
182    /// of the given alignment
183    ///
184    /// # Examples
185    ///
186    /// ```
187    /// # use canadensis_bit_length_set::BitLengthSet;
188    /// let lengths = BitLengthSet::from_lengths([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap();
189    /// let padded = lengths.pad_to_alignment(8);
190    ///
191    /// let expected = BitLengthSet::from_lengths([0, 8, 16]).unwrap();
192    /// assert_eq!(padded.expand(), expected.expand());
193    /// ```
194    pub fn pad_to_alignment(self, alignment: u32) -> BitLengthSet {
195        BitLengthSet {
196            operator: Operator::Padding {
197                child: Box::new(self.operator),
198                alignment,
199            },
200        }
201    }
202
203    /// Converts this bit length set into a new set that represents a repetition of these values
204    /// a fixed number of times
205    ///
206    /// # Examples
207    ///
208    /// ## Single length
209    ///
210    /// ```
211    /// # use canadensis_bit_length_set::BitLengthSet;
212    /// let length = BitLengthSet::single(12);
213    /// let repeated = length.repeat(4);
214    ///
215    /// let expected = BitLengthSet::single(12 * 4);
216    /// assert_eq!(repeated.expand(), expected.expand());
217    /// ```
218    ///
219    /// ## Multiple lengths
220    ///
221    /// ```
222    /// # use canadensis_bit_length_set::BitLengthSet;
223    /// let lengths = BitLengthSet::from_lengths([0, 1, 8]).unwrap();
224    /// let repeated = lengths.repeat(4);
225    ///
226    /// let expected = BitLengthSet::from_lengths(
227    ///     [0, 1, 2, 3, 4, 8, 9, 10, 11, 16, 17, 18, 24, 25, 32]
228    /// ).unwrap();
229    /// assert_eq!(repeated.expand(), expected.expand());
230    /// ```
231    ///
232    pub fn repeat(self, count: u64) -> BitLengthSet {
233        BitLengthSet {
234            operator: Operator::Repeat {
235                child: Box::new(self.operator),
236                count,
237            },
238        }
239    }
240
241    /// Converts this bit length set into a new set that represents a repetition of these values
242    /// zero times up to an inclusive maximum count
243    ///
244    /// # Examples
245    ///
246    /// ## Single length
247    ///
248    /// ```
249    /// # use canadensis_bit_length_set::BitLengthSet;
250    /// let lengths = BitLengthSet::single(3);
251    /// let repeated = lengths.repeat_range(..=8);
252    ///
253    /// let expected = BitLengthSet::from_lengths([0, 3, 6, 9, 12, 15, 18, 21, 24]).unwrap();
254    /// assert_eq!(repeated.expand(), expected.expand());
255    /// ```
256    ///
257    /// ## Multiple lengths
258    ///
259    /// ```
260    /// # use canadensis_bit_length_set::BitLengthSet;
261    /// let lengths = BitLengthSet::from_lengths([1, 2, 4]).unwrap();
262    /// let repeated = lengths.repeat_range(..=2);
263    ///
264    /// let expected = BitLengthSet::from_lengths([0, 1, 2, 3, 4, 5, 6, 8]).unwrap();
265    /// assert_eq!(repeated.expand(), expected.expand());
266    /// ```
267    pub fn repeat_range(self, count: RangeToInclusive<u64>) -> BitLengthSet {
268        BitLengthSet {
269            operator: Operator::RangeRepeat {
270                child: Box::new(self.operator),
271                count,
272            },
273        }
274    }
275
276    /// Extends this bit length set, so that this set represents a concatenation of this set
277    /// followed by other sets
278    ///
279    /// # Examples
280    ///
281    /// ```
282    /// # use canadensis_bit_length_set::{BitLengthSet, bit_length};
283    ///
284    /// let combined = bit_length![0, 8].concatenate([bit_length![12]]);
285    /// let expected = bit_length![12, 20];
286    /// assert_eq!(combined.expand(), expected.expand());
287    /// ```
288    ///
289    /// ```
290    /// # use canadensis_bit_length_set::{BitLengthSet, bit_length};
291    ///
292    /// let combined = bit_length![0, 1, 3].concatenate([bit_length![5, 13]]);
293    /// let expected = bit_length![5, 6, 8, 13, 14, 16];
294    /// assert_eq!(combined.expand(), expected.expand());
295    /// ```
296    pub fn concatenate<I>(mut self, others: I) -> BitLengthSet
297    where
298        I: IntoIterator<Item = BitLengthSet>,
299    {
300        self.extend(others);
301        self
302    }
303
304    /// Converts this bit length set into a new set that is the union of this set and the provided
305    /// other sets
306    ///
307    /// This is uses to represent a union (or enum in Rust)
308    ///
309    /// # Examples
310    ///
311    /// ```
312    /// # use canadensis_bit_length_set::{BitLengthSet, bit_length};
313    ///
314    /// let combined = bit_length![0, 1, 3, 24].unite([bit_length![3, 8]]);
315    /// let expected = bit_length![0, 1, 3, 8, 24];
316    /// assert_eq!(combined.expand(), expected.expand());
317    /// ```
318    pub fn unite<I>(self, others: I) -> BitLengthSet
319    where
320        I: IntoIterator<Item = BitLengthSet>,
321    {
322        let other_operators = others.into_iter().map(|set| set.operator);
323        BitLengthSet {
324            operator: Operator::Union {
325                children: iter::once(self.operator).chain(other_operators).collect(),
326            },
327        }
328    }
329
330    /// Checks that the expanded form of this set has the same properties as calculated based on
331    /// the internal representation of this set
332    pub fn validate_numerically(&self) {
333        self.operator.validate_numerically()
334    }
335
336    /// Returns true if this set has the same structure of operators as another set
337    ///
338    /// If this function returns true, the expanded forms of self and other are equal. If this
339    /// function returns false, the expanded forms of self and other may or may not be equal.
340    fn structural_equal(&self, other: &Self) -> bool {
341        self.operator.structural_equal(&other.operator)
342    }
343}
344
345impl Default for BitLengthSet {
346    /// Returns the default bit length set, which contains the value 0
347    fn default() -> Self {
348        BitLengthSet::single(0)
349    }
350}
351
352impl Rem<u64> for BitLengthSet {
353    type Output = BitLengthSet;
354
355    /// Calculates the elementwise modulo of each value in this set
356    fn rem(self, rhs: u64) -> Self::Output {
357        // Delegate to version that takes &self
358        Rem::rem(&self, rhs)
359    }
360}
361
362impl Rem<u64> for &'_ BitLengthSet {
363    type Output = BitLengthSet;
364
365    /// Calculates the elementwise modulo of each value in this set
366    ///
367    /// # Examples
368    ///
369    /// ```
370    /// # use canadensis_bit_length_set::{BitLengthSet, bit_length};
371    ///
372    /// assert_eq!((bit_length![0] % 12345).expand(), bit_length![0].expand());
373    /// assert_eq!((bit_length![34] % 17).expand(), bit_length![0].expand());
374    /// assert_eq!((bit_length![8, 12, 16] % 8).expand(), bit_length![0, 4].expand());
375    /// assert_eq!((bit_length![0, 3, 8, 9, 27] % 8).expand(), bit_length![0, 1, 3].expand());
376    ///
377    /// ```
378    fn rem(self, rhs: u64) -> Self::Output {
379        let result = self.operator.modulo(rhs);
380        debug_assert!(!result.is_empty());
381        BitLengthSet {
382            operator: Operator::Leaf(result),
383        }
384    }
385}
386
387impl Extend<BitLengthSet> for BitLengthSet {
388    /// Extends this bit length set, so that this set represents a concatenation of this set
389    /// followed by other sets
390    ///
391    /// This is equivalent to [`concatenate`](#method.concatenate).
392    fn extend<T: IntoIterator<Item = BitLengthSet>>(&mut self, iter: T) {
393        let other_operators = iter.into_iter().map(|set| set.operator);
394        // Take out the operator from self and temporarily replace it with an invalid empty operator
395        let self_operator = mem::replace(&mut self.operator, Operator::Leaf(BTreeSet::default()));
396        self.operator = Operator::Concatenate {
397            children: iter::once(self_operator).chain(other_operators).collect(),
398        }
399    }
400}
401
402impl PartialEq<Self> for BitLengthSet {
403    fn eq(&self, other: &Self) -> bool {
404        // There may be a more optimized way to do this
405        if self.structural_equal(other) {
406            true
407        } else {
408            self.expand() == other.expand()
409        }
410    }
411}
412
413impl Eq for BitLengthSet {}
414
415impl PartialOrd for BitLengthSet {
416    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
417        Some(self.cmp(other))
418    }
419}
420
421impl Ord for BitLengthSet {
422    fn cmp(&self, other: &Self) -> Ordering {
423        // There may be a more optimized way to do this, without expanding the sets
424        self.expand().cmp(&other.expand())
425    }
426}
427
428/// A convenience macro for creating a `BitLengthSet`
429///
430/// This macro takes one or more arguments and evaluates to a `BitLengthSet` value.
431///
432/// # Examples
433///
434/// ```
435/// # use canadensis_bit_length_set::bit_length;
436/// bit_length![8];
437/// bit_length![0, 8, 10];
438/// bit_length![0, 8, 10,];
439/// ```
440///
441/// This macro will produce a compiler error if you attempt to call it with no arguments:
442///
443/// ```compile_fail
444/// # use canadensis_bit_length_set::bit_length;
445/// bit_length![];
446/// ```
447///
448#[macro_export]
449macro_rules! bit_length {
450    {$single:expr} => {
451        $crate::BitLengthSet::single($single)
452    };
453    {$first:expr, $($others:expr),+ $(,)?} => {
454        $crate::BitLengthSet::from_lengths([$first, $($others),+]).unwrap()
455    };
456}