Macro range_set::range_set

source ·
macro_rules! range_set {
    () => { ... };
    ( ; $len:expr ) => { ... };
    ( $( $num:tt ),+ ) => { ... };
    ( $( $num:tt ),+ ; $len:expr ) => { ... };
    ( $( $start:tt $( ..= $end:tt )? $( as $range_keyword:tt )? ),+ ) => { ... };
    ( $( $start:tt $( ..= $end:tt )? $( as $range_keyword:tt )? ),+ ; $len:expr ) => { ... };
}
Expand description

Convenient macro to construct RangeSets without needing bulky notation like ::<[RangeInclusive<_>; _]>. The macro allows a mix of numbers and inclusive ranges, with an optional length at the end for the smallvec array size. If the length is not specified, it will default to 4.

The implementation guarantees O(n) construction time for lists of non-adjacent mix of increasing-ranges and numbers in increasing order. See RangeSet::from_ranges for more information about this optimization. Single numbers are transformed into one-element inclusive ranges (5 becomes 5..=5).

Separately, the implementation guarantees O(n) construction time for lists of numbers (not ranges) sorted in increasing order and deduplicated. See [RangeSet::from_elements] for more information about this optimization.

All other cases are reasonably performant, O(n * log(n)) on average.


let case1 = RangeSet::<[RangeInclusive<u32>; 3]>::from_valid_ranges ([0..=0, 2..=5]).unwrap();
let case2 = RangeSet::<[RangeInclusive<u32>; 4]>::from_valid_ranges ([1..=3, 6..=15, 40..=40, 42..=50]).unwrap();
const FIVE: u32 = 5;
let some_func = |x: u32| x;
let your_var = 0;

// The fastest format to use is non-adjacent, increasing ranges in increasing order.
assert_eq!(range_set![0, 2..=5; 3], case1);
assert_eq!(range_set![1..=3, 6..=15, 40, 42..=50; 4], case2);

// The smallvec size is optional, and defaults to 4.
assert_eq!(range_set![1..=3, 6..=15, 40, 42..=50], case2);

// A wide variety of other formats are available. Complex epressions need to be surrounded
// by parentheses.
assert_eq!(range_set![0, 2, 3..=5; 3], case1);
assert_eq!(range_set![0, 2, (1 + 2), 4, FIVE; 3], case1);
assert_eq!(range_set![0, 2, (some_func(3)), 4, 5; 3], case1);
assert_eq!(range_set![your_var, 2..=(some_func(5)); 3], case1);

// Expressions that return ranges need to be marked using "as range":
let my_range = 2..=5;
assert_eq!(range_set![0, my_range as range; 3], case1);

// Empty lists are still allowed. Rust may have trouble inferring the number type/size
// in some situations.
assert_eq!(range_set![], RangeSet::<[RangeInclusive<u32>; 4]>::new());
assert_eq!(range_set![; 3], RangeSet::<[RangeInclusive<u32>; 3]>::new());