range_set_blaze/sorted_disjoint.rs
1use crate::map::ValueRef;
2use crate::range_values::{MapIntoRangesIter, MapRangesIter, RangeValuesToRangesIter};
3use crate::ranges_iter::RangesIter;
4use crate::sorted_disjoint_map::IntoString;
5use crate::RangeSetBlaze;
6use crate::{IntoRangesIter, UnionIter, UnionMerge};
7use alloc::string::String;
8use core::array;
9use core::{
10 iter::FusedIterator,
11 ops::{self, RangeInclusive},
12};
13
14use crate::SortedDisjointMap;
15
16use crate::{
17 DifferenceMerge, DynSortedDisjoint, Integer, IntersectionMerge, NotIter, SymDiffIter,
18 SymDiffMerge,
19};
20
21/// Used internally. Marks iterators that provide ranges sorted by start, but
22/// that are not necessarily disjoint. The ranges are non-empty.
23pub trait SortedStarts<T: Integer>: Iterator<Item = RangeInclusive<T>> + FusedIterator {}
24
25/// Marks iterators that provide ranges that are sorted by start and disjoint. Set operations on
26/// iterators that implement this trait can be performed in linear time.
27///
28/// # Table of Contents
29/// * [`SortedDisjoint` Constructors](#sorteddisjoint-constructors)
30/// * [Examples](#constructor-examples)
31/// * [`SortedDisjoint` Set Operations](#sorteddisjoint-set-operations)
32/// * [Performance](#performance)
33/// * [Examples](#examples)
34/// * [How to mark your type as `SortedDisjoint`](#how-to-mark-your-type-as-sorteddisjoint)
35/// * [Example – Find the ordinal weekdays in September 2023](#example--find-the-ordinal-weekdays-in-september-2023)
36///
37/// # `SortedDisjoint` Constructors
38///
39/// You'll usually construct a `SortedDisjoint` iterator from a [`RangeSetBlaze`] or a [`CheckSortedDisjoint`].
40/// Here is a summary table, followed by [examples](#constructor-examples). You can also [define your own
41/// `SortedDisjoint`](#how-to-mark-your-type-as-sorteddisjoint).
42///
43/// | Input type | Method |
44/// |------------|--------|
45/// | [`RangeSetBlaze`] | [`ranges`] |
46/// | [`RangeSetBlaze`] | [`into_ranges`] |
47/// | sorted & disjoint ranges | [`CheckSortedDisjoint::new`] |
48/// | *your iterator type* | *[How to mark your type as `SortedDisjoint`][1]* |
49///
50/// [`ranges`]: RangeSetBlaze::ranges
51/// [`into_ranges`]: RangeSetBlaze::into_ranges
52/// [1]: #how-to-mark-your-type-as-sorteddisjoint
53/// [`RangesIter`]: crate::RangesIter
54/// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
55///
56/// ## Constructor Examples
57/// ```
58/// use range_set_blaze::prelude::*;
59///
60/// // RangeSetBlaze's .ranges() and .into_ranges()
61/// let r = RangeSetBlaze::from_iter([3, 2, 1, 100, 1]);
62/// let a = r.ranges();
63/// assert!(a.into_string() == "1..=3, 100..=100");
64/// // 'into_ranges' takes ownership of the 'RangeSetBlaze'
65/// let a = RangeSetBlaze::from_iter([3, 2, 1, 100, 1]).into_ranges();
66/// assert!(a.into_string() == "1..=3, 100..=100");
67///
68/// // CheckSortedDisjoint -- unsorted or overlapping input ranges will cause a panic.
69/// let a = CheckSortedDisjoint::new([1..=3, 100..=100]);
70/// assert!(a.into_string() == "1..=3, 100..=100");
71/// ```
72///
73/// # `SortedDisjoint` Set Operations
74///
75/// You can perform set operations on `SortedDisjoint`s using operators.
76///
77/// | Set Operators | Operator | Multiway (same type) | Multiway (different types) |
78/// |------------------------------------|-------------|---------------------------------------------------|--------------------------------------|
79/// | [`union`] | [`a` | `b`] | `[a, b, c].`[`union`][multiway_union]`() ` | [`union_dyn!`]`(a, b, c)` |
80/// | [`intersection`] | [`a & b`] | `[a, b, c].`[`intersection`][multiway_intersection]`() ` | [`intersection_dyn!`]`(a, b, c)`|
81/// | [`difference`] | [`a - b`] | *n/a* | *n/a* |
82/// | [`symmetric_difference`] | [`a ^ b`] | `[a, b, c].`[`symmetric_difference`][multiway_symmetric_difference]`() ` | [`symmetric_difference_dyn!`]`(a, b, c)` |
83/// | [`complement`] | [`!a`] | *n/a* | *n/a* |
84///
85/// [`a` | `b`]: trait.SortedDisjoint.html#method.union
86/// [`a & b`]: trait.SortedDisjoint.html#method.intersection
87/// [`a - b`]: trait.SortedDisjoint.html#method.difference
88/// [`a ^ b`]: trait.SortedDisjoint.html#method.symmetric_difference
89/// [`!a`]: trait.SortedDisjoint.html#method.complement
90/// [multiway_union]: trait.MultiwaySortedDisjoint.html#method.union
91/// [multiway_intersection]: trait.MultiwaySortedDisjoint.html#method.intersection
92/// [multiway_symmetric_difference]: trait.MultiwaySortedDisjoint.html#method.symmetric_difference
93/// [`union_dyn!`]: macro.union_dyn.html
94/// [`intersection_dyn!`]: macro.intersection_dyn.html
95/// [`symmetric_difference_dyn!`]: macro.symmetric_difference_dyn.html
96///
97/// ## Performance
98///
99/// Every operation is implemented as a single pass over the sorted & disjoint ranges, with minimal memory.
100///
101/// This is true even when applying multiple operations. The last example below demonstrates this.
102///
103/// ## Examples
104///
105/// ```
106/// use range_set_blaze::prelude::*;
107///
108/// let a0 = RangeSetBlaze::from_iter([1..=2, 5..=100]);
109/// let b0 = RangeSetBlaze::from_iter([2..=6]);
110///
111/// // 'union' method and 'to_string' method
112/// let (a, b) = (a0.ranges(), b0.ranges());
113/// let result = a.union(b);
114/// assert_eq!(result.into_string(), "1..=100");
115///
116/// // '|' operator and 'equal' method
117/// let (a, b) = (a0.ranges(), b0.ranges());
118/// let result = a | b;
119/// assert!(result.equal(CheckSortedDisjoint::new([1..=100])));
120///
121/// // multiway union of same type
122/// let c0 = RangeSetBlaze::from_iter([2..=2, 6..=200]);
123/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
124/// let result = [a, b, c].union();
125/// assert_eq!(result.into_string(), "1..=200");
126///
127/// // multiway union of different types
128/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
129/// let result = union_dyn!(a, b, !c);
130/// assert_eq!(result.into_string(), "-2147483648..=100, 201..=2147483647");
131///
132/// // Applying multiple operators makes only one pass through the inputs with minimal memory.
133/// let (a, b, c) = (a0.ranges(), b0.ranges(), c0.ranges());
134/// let result = a - (b | c);
135/// assert!(result.into_string() == "1..=1");
136/// ```
137///
138/// # How to mark your type as `SortedDisjoint`
139///
140/// To mark your iterator type as `SortedDisjoint`, you implement the `SortedStarts` and `SortedDisjoint` traits.
141/// This is your promise to the compiler that your iterator will provide inclusive ranges that are
142/// disjoint and sorted by start.
143///
144/// When you do this, your iterator will get access to the
145/// efficient set operations methods, such as [`intersection`] and [`complement`]. The example below shows this.
146///
147/// > To use operators such as `&` and `!`, you must also implement the [`BitAnd`], [`Not`], etc. traits.
148/// >
149/// > If you want others to use your marked iterator type, reexport:
150/// > `pub use range_set_blaze::{SortedDisjoint, SortedStarts};`
151///
152/// [`BitAnd`]: core::ops::BitAnd
153/// [`Not`]: core::ops::Not
154/// [`intersection`]: SortedDisjoint::intersection
155/// [`complement`]: SortedDisjoint::complement
156/// [`union`]: SortedDisjoint::union
157/// [`symmetric_difference`]: SortedDisjoint::symmetric_difference
158/// [`difference`]: SortedDisjoint::difference
159/// [`to_string`]: SortedDisjoint::to_string
160/// [`equal`]: SortedDisjoint::equal
161/// [multiway_union]: crate::MultiwaySortedDisjoint::union
162/// [multiway_intersection]: crate::MultiwaySortedDisjoint::intersection
163///
164/// ## Example -- Find the ordinal weekdays in September 2023
165/// ```
166/// use core::ops::RangeInclusive;
167/// use core::iter::FusedIterator;
168/// pub use range_set_blaze::{SortedDisjoint, SortedStarts};
169///
170/// // Ordinal dates count January 1 as day 1, February 1 as day 32, etc.
171/// struct OrdinalWeekends2023 {
172/// next_range: RangeInclusive<i32>,
173/// }
174///
175/// // We promise the compiler that our iterator will provide
176/// // ranges that are sorted and disjoint.
177/// impl FusedIterator for OrdinalWeekends2023 {}
178/// impl SortedStarts<i32> for OrdinalWeekends2023 {}
179/// impl SortedDisjoint<i32> for OrdinalWeekends2023 {}
180///
181/// impl OrdinalWeekends2023 {
182/// fn new() -> Self {
183/// Self { next_range: 0..=1 }
184/// }
185/// }
186/// impl Iterator for OrdinalWeekends2023 {
187/// type Item = RangeInclusive<i32>;
188/// fn next(&mut self) -> Option<Self::Item> {
189/// let (start, end) = self.next_range.clone().into_inner();
190/// if start > 365 {
191/// None
192/// } else {
193/// self.next_range = (start + 7)..=(end + 7);
194/// Some(start.max(1)..=end.min(365))
195/// }
196/// }
197/// }
198///
199/// use range_set_blaze::prelude::*;
200///
201/// let weekends = OrdinalWeekends2023::new();
202/// let september = CheckSortedDisjoint::new([244..=273]);
203/// let september_weekdays = september.intersection(weekends.complement());
204/// assert_eq!(
205/// september_weekdays.into_string(),
206/// "244..=244, 247..=251, 254..=258, 261..=265, 268..=272"
207/// );
208/// ```
209pub trait SortedDisjoint<T: Integer>: SortedStarts<T> {
210 // I think this is 'Sized' because will sometimes want to create a struct (e.g. BitOrIter) that contains a field of this type
211
212 /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their union.
213 ///
214 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
215 ///
216 /// # Examples
217 ///
218 /// ```
219 /// use range_set_blaze::prelude::*;
220 ///
221 /// let a = CheckSortedDisjoint::new([1..=1]);
222 /// let b = RangeSetBlaze::from_iter([2..=2]).into_ranges();
223 /// let union = a.union(b);
224 /// assert_eq!(union.into_string(), "1..=2");
225 ///
226 /// // Alternatively, we can use "|" because CheckSortedDisjoint defines
227 /// // ops::bitor as SortedDisjoint::union.
228 /// let a = CheckSortedDisjoint::new([1..=1]);
229 /// let b = RangeSetBlaze::from_iter([2..=2]).into_ranges();
230 /// let union = a | b;
231 /// assert_eq!(union.into_string(), "1..=2");
232 /// ```
233 #[inline]
234 fn union<R>(self, other: R) -> UnionMerge<T, Self, R::IntoIter>
235 where
236 R: IntoIterator<Item = Self::Item>,
237 R::IntoIter: SortedDisjoint<T>,
238 Self: Sized,
239 {
240 UnionMerge::new2(self, other.into_iter())
241 }
242
243 /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their intersection.
244 ///
245 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
246 ///
247 /// # Examples
248 ///
249 /// ```
250 /// use range_set_blaze::prelude::*;
251 ///
252 /// let a = CheckSortedDisjoint::new([1..=2]);
253 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
254 /// let intersection = a.intersection(b);
255 /// assert_eq!(intersection.into_string(), "2..=2");
256 ///
257 /// // Alternatively, we can use "&" because CheckSortedDisjoint defines
258 /// // ops::bitand as SortedDisjoint::intersection.
259 /// let a = CheckSortedDisjoint::new([1..=2]);
260 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
261 /// let intersection = a & b;
262 /// assert_eq!(intersection.into_string(), "2..=2");
263 /// ```
264 #[inline]
265 fn intersection<R>(self, other: R) -> IntersectionMerge<T, Self, R::IntoIter>
266 where
267 R: IntoIterator<Item = Self::Item>,
268 R::IntoIter: SortedDisjoint<T>,
269 Self: Sized,
270 {
271 !(self.complement() | other.into_iter().complement())
272 }
273
274 /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator of their set difference.
275 ///
276 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
277 ///
278 /// # Examples
279 ///
280 /// ```
281 /// use range_set_blaze::prelude::*;
282 ///
283 /// let a = CheckSortedDisjoint::new([1..=2]);
284 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
285 /// let difference = a.difference(b);
286 /// assert_eq!(difference.into_string(), "1..=1");
287 ///
288 /// // Alternatively, we can use "-" because CheckSortedDisjoint defines
289 /// // ops::sub as SortedDisjoint::difference.
290 /// let a = CheckSortedDisjoint::new([1..=2]);
291 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
292 /// let difference = a - b;
293 /// assert_eq!(difference.into_string(), "1..=1");
294 /// ```
295 #[inline]
296 fn difference<R>(self, other: R) -> DifferenceMerge<T, Self, R::IntoIter>
297 where
298 R: IntoIterator<Item = Self::Item>,
299 R::IntoIter: SortedDisjoint<T>,
300 Self: Sized,
301 {
302 !(self.complement() | other.into_iter())
303 }
304
305 /// Given a [`SortedDisjoint`] iterator, efficiently returns a [`SortedDisjoint`] iterator of its complement.
306 ///
307 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
308 ///
309 /// # Examples
310 ///
311 /// ```
312 /// use range_set_blaze::prelude::*;
313 ///
314 /// let a = CheckSortedDisjoint::new([10_u8..=20, 100..=200]);
315 /// let complement = a.complement();
316 /// assert_eq!(complement.into_string(), "0..=9, 21..=99, 201..=255");
317 ///
318 /// // Alternatively, we can use "!" because CheckSortedDisjoint defines
319 /// // `ops::Not` as `SortedDisjoint::complement`.
320 /// let a = CheckSortedDisjoint::new([10_u8..=20, 100..=200]);
321 /// let complement = !a;
322 /// assert_eq!(complement.into_string(), "0..=9, 21..=99, 201..=255");
323 /// ```
324 #[inline]
325 fn complement(self) -> NotIter<T, Self>
326 where
327 Self: Sized,
328 {
329 NotIter::new(self)
330 }
331
332 /// Given two [`SortedDisjoint`] iterators, efficiently returns a [`SortedDisjoint`] iterator
333 /// of their symmetric difference.
334 ///
335 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
336 /// # Examples
337 ///
338 /// ```
339 /// use range_set_blaze::prelude::*;
340 ///
341 /// let a = CheckSortedDisjoint::new([1..=2]);
342 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
343 /// let symmetric_difference = a.symmetric_difference(b);
344 /// assert_eq!(symmetric_difference.into_string(), "1..=1, 3..=3");
345 ///
346 /// // Alternatively, we can use "^" because CheckSortedDisjoint defines
347 /// // ops::bitxor as SortedDisjoint::symmetric_difference.
348 /// let a = CheckSortedDisjoint::new([1..=2]);
349 /// let b = RangeSetBlaze::from_iter([2..=3]).into_ranges();
350 /// let symmetric_difference = a ^ b;
351 /// assert_eq!(symmetric_difference.into_string(), "1..=1, 3..=3");
352 /// ```
353 #[inline]
354 fn symmetric_difference<R>(self, other: R) -> SymDiffMerge<T, Self, R::IntoIter>
355 where
356 R: IntoIterator<Item = Self::Item>,
357 R::IntoIter: SortedDisjoint<T>,
358 <R as IntoIterator>::IntoIter:,
359 Self: Sized,
360 {
361 let result: SymDiffIter<T, crate::Merge<T, Self, <R as IntoIterator>::IntoIter>> =
362 SymDiffIter::new2(self, other.into_iter());
363 result
364 }
365
366 /// Given two [`SortedDisjoint`] iterators, efficiently tells if they are equal. Unlike most equality testing in Rust,
367 /// this method takes ownership of the iterators and consumes them.
368 ///
369 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
370 ///
371 /// # Examples
372 ///
373 /// ```
374 /// use range_set_blaze::prelude::*;
375 ///
376 /// let a = CheckSortedDisjoint::new([1..=2]);
377 /// let b = RangeSetBlaze::from_iter([1..=2]).into_ranges();
378 /// assert!(a.equal(b));
379 /// ```
380 fn equal<R>(self, other: R) -> bool
381 where
382 R: IntoIterator<Item = Self::Item>,
383 R::IntoIter: SortedDisjoint<T>,
384 Self: Sized,
385 {
386 itertools::equal(self, other)
387 }
388
389 /// Deprecated. Use [`into_string`] instead.
390 ///
391 /// [`into_string`]: trait.IntoString.html
392 #[deprecated(since = "0.2.0", note = "Use `into_string` instead")]
393 fn to_string(self) -> String
394 where
395 Self: Sized,
396 {
397 self.into_string()
398 }
399
400 /// Returns `true` if the set contains no elements.
401 ///
402 /// # Examples
403 ///
404 /// ```
405 /// use range_set_blaze::prelude::*;
406 ///
407 /// let a = CheckSortedDisjoint::new([1..=2]);
408 /// assert!(!a.is_empty());
409 /// ```
410 #[inline]
411 #[allow(clippy::wrong_self_convention)]
412 fn is_empty(mut self) -> bool
413 where
414 Self: Sized,
415 {
416 self.next().is_none()
417 }
418
419 /// Returns `true` if the set is a subset of another,
420 /// i.e., `other` contains at least all the elements in `self`.
421 ///
422 /// # Examples
423 ///
424 /// ```
425 /// use range_set_blaze::prelude::*;
426 ///
427 /// let sup = CheckSortedDisjoint::new([1..=3]);
428 /// let set: CheckSortedDisjoint<i32, _> = [].into();
429 /// assert_eq!(set.is_subset(sup), true);
430 ///
431 /// let sup = CheckSortedDisjoint::new([1..=3]);
432 /// let set = CheckSortedDisjoint::new([2..=2]);
433 /// assert_eq!(set.is_subset(sup), true);
434 ///
435 /// let sup = CheckSortedDisjoint::new([1..=3]);
436 /// let set = CheckSortedDisjoint::new([2..=2, 4..=4]);
437 /// assert_eq!(set.is_subset(sup), false);
438 /// ```
439 #[must_use]
440 #[inline]
441 #[allow(clippy::wrong_self_convention)]
442 fn is_subset<R>(self, other: R) -> bool
443 where
444 R: IntoIterator<Item = Self::Item>,
445 R::IntoIter: SortedDisjoint<T>,
446 Self: Sized,
447 {
448 // LATER: Could be made a little more efficient by coding the logic directly into the iterators.
449 self.difference(other).is_empty()
450 }
451
452 /// Returns `true` if the set is a superset of another,
453 /// i.e., `self` contains at least all the elements in `other`.
454 ///
455 /// # Examples
456 ///
457 /// ```
458 /// use range_set_blaze::RangeSetBlaze;
459 ///
460 /// let sub = RangeSetBlaze::from_iter([1, 2]);
461 /// let mut set = RangeSetBlaze::new();
462 ///
463 /// assert_eq!(set.is_superset(&sub), false);
464 ///
465 /// set.insert(0);
466 /// set.insert(1);
467 /// assert_eq!(set.is_superset(&sub), false);
468 ///
469 /// set.insert(2);
470 /// assert_eq!(set.is_superset(&sub), true);
471 /// ```
472 #[inline]
473 #[must_use]
474 #[allow(clippy::wrong_self_convention)]
475 fn is_superset<R>(self, other: R) -> bool
476 where
477 R: IntoIterator<Item = Self::Item>,
478 R::IntoIter: SortedDisjoint<T>,
479 Self: Sized,
480 {
481 other.into_iter().is_subset(self)
482 }
483
484 /// Returns `true` if `self` has no elements in common with `other`.
485 /// This is equivalent to checking for an empty intersection.
486 ///
487 /// # Examples
488 ///
489 /// ```
490 /// use range_set_blaze::RangeSetBlaze;
491 ///
492 /// let a = RangeSetBlaze::from_iter([1..=3]);
493 /// let mut b = RangeSetBlaze::new();
494 ///
495 /// assert_eq!(a.is_disjoint(&b), true);
496 /// b.insert(4);
497 /// assert_eq!(a.is_disjoint(&b), true);
498 /// b.insert(1);
499 /// assert_eq!(a.is_disjoint(&b), false);
500 /// ```
501 #[must_use]
502 #[inline]
503 #[allow(clippy::wrong_self_convention)]
504 fn is_disjoint<R>(self, other: R) -> bool
505 where
506 R: IntoIterator<Item = Self::Item>,
507 R::IntoIter: SortedDisjoint<T>,
508 Self: Sized,
509 {
510 self.intersection(other).is_empty()
511 }
512
513 /// Create a [`RangeSetBlaze`] from a [`SortedDisjoint`] iterator.
514 ///
515 /// *For more about constructors and performance, see [`RangeSetBlaze` Constructors](struct.RangeSetBlaze.html#rangesetblaze-constructors).*
516 ///
517 /// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
518 ///
519 /// # Examples
520 ///
521 /// ```
522 /// use range_set_blaze::prelude::*;
523 ///
524 /// let a0 = RangeSetBlaze::from_sorted_disjoint(CheckSortedDisjoint::new([-10..=-5, 1..=2]));
525 /// let a1: RangeSetBlaze<i32> = CheckSortedDisjoint::new([-10..=-5, 1..=2]).into_range_set_blaze();
526 /// assert!(a0 == a1 && a0.to_string() == "-10..=-5, 1..=2");
527 /// ```
528 fn into_range_set_blaze(self) -> RangeSetBlaze<T>
529 where
530 Self: Sized,
531 {
532 RangeSetBlaze::from_sorted_disjoint(self)
533 }
534}
535
536/// Gives the [`SortedDisjoint`] trait to any iterator of ranges. The iterator will panic
537/// if/when it finds that the ranges are not actually sorted and disjoint.
538///
539/// [SortedDisjoint]: crate::SortedDisjoint.html#table-of-contents
540///
541/// # Performance
542///
543/// All checking is done at runtime, but it should still be fast.
544///
545/// # Example
546///
547/// ```
548/// use range_set_blaze::prelude::*;
549///
550/// let a = CheckSortedDisjoint::new([1..=2, 5..=100]);
551/// let b = CheckSortedDisjoint::new([2..=6]);
552/// let union = a | b;
553/// assert_eq!(union.into_string(), "1..=100");
554/// ```
555///
556/// Here the ranges are not sorted and disjoint, so the iterator will panic.
557///```should_panic
558/// use range_set_blaze::prelude::*;
559///
560/// let a = CheckSortedDisjoint::new([1..=2, 5..=100]);
561/// let b = CheckSortedDisjoint::new([2..=6,-10..=-5]);
562/// let union = a | b;
563/// assert_eq!(union.into_string(), "1..=100");
564/// ```
565#[derive(Debug, Clone)]
566#[must_use = "iterators are lazy and do nothing unless consumed"]
567#[allow(clippy::module_name_repetitions)]
568pub struct CheckSortedDisjoint<T, I>
569where
570 T: Integer,
571 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
572{
573 pub(crate) iter: I,
574 prev_end: Option<T>,
575 seen_none: bool,
576}
577
578impl<T, I> CheckSortedDisjoint<T, I>
579where
580 T: Integer,
581 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
582{
583 /// Creates a new [`CheckSortedDisjoint`] from an iterator of ranges. See [`CheckSortedDisjoint`] for details and examples.
584 #[inline]
585 pub fn new<J: IntoIterator<IntoIter = I>>(iter: J) -> Self {
586 Self {
587 iter: iter.into_iter(),
588 prev_end: None,
589 seen_none: false,
590 }
591 }
592}
593
594impl<T> Default for CheckSortedDisjoint<T, array::IntoIter<RangeInclusive<T>, 0>>
595where
596 T: Integer,
597{
598 // Default is an empty iterator.
599 fn default() -> Self {
600 Self::new([])
601 }
602}
603
604impl<T, I> FusedIterator for CheckSortedDisjoint<T, I>
605where
606 T: Integer,
607 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
608{
609}
610
611impl<T, I> Iterator for CheckSortedDisjoint<T, I>
612where
613 T: Integer,
614 I: Iterator<Item = RangeInclusive<T>> + FusedIterator,
615{
616 type Item = RangeInclusive<T>;
617
618 fn next(&mut self) -> Option<Self::Item> {
619 let next = self.iter.next();
620
621 let Some(range) = next.as_ref() else {
622 self.seen_none = true;
623 return next;
624 };
625
626 assert!(
627 !self.seen_none,
628 "iterator cannot return Some after returning None"
629 );
630 let (start, end) = range.clone().into_inner();
631 assert!(start <= end, "start must be less or equal to end");
632 if let Some(prev_end) = self.prev_end {
633 assert!(
634 prev_end < T::max_value() && prev_end.add_one() < start,
635 "ranges must be disjoint"
636 );
637 }
638 self.prev_end = Some(end);
639
640 next
641 }
642
643 fn size_hint(&self) -> (usize, Option<usize>) {
644 self.iter.size_hint()
645 }
646}
647
648impl<T: Integer, const N: usize> From<[RangeInclusive<T>; N]>
649 for CheckSortedDisjoint<T, array::IntoIter<RangeInclusive<T>, N>>
650{
651 /// Deprecated: Use `new` instead.
652 fn from(arr: [RangeInclusive<T>; N]) -> Self {
653 Self::new(arr)
654 }
655}
656
657pub trait AnythingGoes<T: Integer>: Iterator<Item = RangeInclusive<T>> + FusedIterator {}
658impl<T: Integer, I> AnythingGoes<T> for I where I: Iterator<Item = RangeInclusive<T>> + FusedIterator
659{}
660
661macro_rules! impl_sorted_traits_and_ops {
662 ($IterType:ty, $($more_generics:tt)*) => {
663 #[allow(single_use_lifetimes)]
664 impl<$($more_generics)*, T: Integer> SortedStarts<T> for $IterType {}
665 #[allow(single_use_lifetimes)]
666 impl<$($more_generics)*, T: Integer> SortedDisjoint<T> for $IterType {}
667
668 #[allow(single_use_lifetimes)]
669 impl<$($more_generics)*, T: Integer> ops::Not for $IterType
670 {
671 type Output = NotIter<T, Self>;
672
673 fn not(self) -> Self::Output {
674 self.complement()
675 }
676 }
677
678 #[allow(single_use_lifetimes)]
679 impl<$($more_generics)*, T: Integer, R> ops::BitOr<R> for $IterType
680 where
681 R: SortedDisjoint<T>,
682 {
683 type Output = UnionMerge<T, Self, R>;
684
685 fn bitor(self, other: R) -> Self::Output {
686 SortedDisjoint::union(self, other)
687 }
688 }
689
690 #[allow(single_use_lifetimes)]
691 impl<$($more_generics)*, T: Integer, R> ops::Sub<R> for $IterType
692 where
693 R: SortedDisjoint<T>,
694 {
695 type Output = DifferenceMerge<T, Self, R>;
696
697 fn sub(self, other: R) -> Self::Output {
698 // It would be fun to optimize !!self.iter into self.iter
699 // but that would require also considering fields 'start_not' and 'next_time_return_none'.
700 SortedDisjoint::difference(self, other)
701 }
702 }
703
704 #[allow(single_use_lifetimes)]
705 impl<$($more_generics)*, T: Integer, R> ops::BitXor<R> for $IterType
706 where
707 R: SortedDisjoint<T>,
708 {
709 type Output = SymDiffMerge<T, Self, R>;
710
711 #[allow(clippy::suspicious_arithmetic_impl)]
712 fn bitxor(self, other: R) -> Self::Output {
713 SortedDisjoint::symmetric_difference(self, other)
714 }
715 }
716
717 #[allow(single_use_lifetimes)]
718 impl<$($more_generics)*, T: Integer, R> ops::BitAnd<R> for $IterType
719 where
720 R: SortedDisjoint<T>,
721 {
722 type Output = IntersectionMerge<T, Self, R>;
723
724 fn bitand(self, other: R) -> Self::Output {
725 SortedDisjoint::intersection(self, other)
726 }
727 }
728 };
729}
730
731//CheckList: Be sure that these are all tested in 'test_every_sorted_disjoint_method'
732impl_sorted_traits_and_ops!(CheckSortedDisjoint<T, I>, I: AnythingGoes<T>);
733impl_sorted_traits_and_ops!(DynSortedDisjoint<'a, T>, 'a);
734impl_sorted_traits_and_ops!(IntoRangesIter<T>, 'ignore);
735impl_sorted_traits_and_ops!(MapIntoRangesIter<T, V>, V: Eq + Clone);
736impl_sorted_traits_and_ops!(MapRangesIter<'a, T, V>, 'a, V: Eq + Clone);
737impl_sorted_traits_and_ops!(NotIter<T, I>, I: SortedDisjoint<T>);
738impl_sorted_traits_and_ops!(RangesIter<'a, T>, 'a);
739impl_sorted_traits_and_ops!(RangeValuesToRangesIter<T, VR, I>, VR: ValueRef, I: SortedDisjointMap<T, VR>);
740impl_sorted_traits_and_ops!(SymDiffIter<T, I>, I: SortedStarts<T>);
741impl_sorted_traits_and_ops!(UnionIter<T, I>, I: SortedStarts<T>);
742
743// We're not allowed to define methods on outside types, so we only define the traits