periodical/iter/intervals/complement.rs
1//! Complement iterator
2//!
3//! Iterator that returns the [`ComplementResult`] of every interval from the
4//! interval.
5//!
6//! The iterator uses [`Complementable`] to get the complements of the
7//! intervals.
8//!
9//! # Examples
10//!
11//! ```
12//! # use std::error::Error;
13//! # use jiff::Zoned;
14//! # use periodical::ops::ComplementResult;
15//! # use periodical::intervals::absolute::{
16//! # AbsBoundPair, AbsEndBound, AbsFiniteBoundPos, AbsStartBound,
17//! # };
18//! # use periodical::intervals::meta::BoundInclusivity;
19//! # use periodical::iter::intervals::complement::ComplementIteratorDispatcher;
20//! let intervals = [
21//! AbsBoundPair::new(
22//! AbsFiniteBoundPos::new(
23//! "2025-01-01 08:00:00[Europe/Oslo]"
24//! .parse::<Zoned>()?
25//! .timestamp(),
26//! )
27//! .to_start_bound(),
28//! AbsFiniteBoundPos::new(
29//! "2025-01-01 11:00:00[Europe/Oslo]"
30//! .parse::<Zoned>()?
31//! .timestamp(),
32//! )
33//! .to_end_bound(),
34//! ),
35//! AbsBoundPair::new(
36//! AbsFiniteBoundPos::new(
37//! "2025-01-01 12:00:00[Europe/Oslo]"
38//! .parse::<Zoned>()?
39//! .timestamp(),
40//! )
41//! .to_start_bound(),
42//! AbsFiniteBoundPos::new(
43//! "2025-01-01 16:00:00[Europe/Oslo]"
44//! .parse::<Zoned>()?
45//! .timestamp(),
46//! )
47//! .to_end_bound(),
48//! ),
49//! ];
50//!
51//! assert_eq!(
52//! intervals.complement().collect::<Vec<_>>(),
53//! vec![
54//! ComplementResult::Split(
55//! AbsBoundPair::new(
56//! AbsStartBound::InfinitePast,
57//! AbsFiniteBoundPos::new_with_incl(
58//! "2025-01-01 08:00:00[Europe/Oslo]"
59//! .parse::<Zoned>()?
60//! .timestamp(),
61//! BoundInclusivity::Exclusive,
62//! )
63//! .to_end_bound(),
64//! )
65//! .to_emptiable(),
66//! AbsBoundPair::new(
67//! AbsFiniteBoundPos::new_with_incl(
68//! "2025-01-01 11:00:00[Europe/Oslo]"
69//! .parse::<Zoned>()?
70//! .timestamp(),
71//! BoundInclusivity::Exclusive,
72//! )
73//! .to_start_bound(),
74//! AbsEndBound::InfiniteFuture,
75//! )
76//! .to_emptiable(),
77//! ),
78//! ComplementResult::Split(
79//! AbsBoundPair::new(
80//! AbsStartBound::InfinitePast,
81//! AbsFiniteBoundPos::new_with_incl(
82//! "2025-01-01 12:00:00[Europe/Oslo]"
83//! .parse::<Zoned>()?
84//! .timestamp(),
85//! BoundInclusivity::Exclusive,
86//! )
87//! .to_end_bound(),
88//! )
89//! .to_emptiable(),
90//! AbsBoundPair::new(
91//! AbsFiniteBoundPos::new_with_incl(
92//! "2025-01-01 16:00:00[Europe/Oslo]"
93//! .parse::<Zoned>()?
94//! .timestamp(),
95//! BoundInclusivity::Exclusive,
96//! )
97//! .to_start_bound(),
98//! AbsEndBound::InfiniteFuture,
99//! )
100//! .to_emptiable(),
101//! ),
102//! ],
103//! );
104//! # Ok::<(), Box<dyn Error>>(())
105//! ```
106
107use crate::intervals::ops::Complementable;
108use crate::ops::ComplementResult;
109
110/// Dispatcher trait for the [`ComplementIter`] iterator
111pub trait ComplementIteratorDispatcher
112where
113 Self: IntoIterator + Sized,
114 Self::Item: Complementable,
115{
116 /// Creates a [`ComplementIter`] from the collection
117 fn complement(self) -> ComplementIter<Self::IntoIter> {
118 ComplementIter::new(self.into_iter())
119 }
120}
121
122impl<I> ComplementIteratorDispatcher for I
123where
124 I: IntoIterator + Sized,
125 I::Item: Complementable,
126{
127}
128
129/// Returns the interval complement of each element
130#[derive(Debug, Clone, Hash)]
131pub struct ComplementIter<I> {
132 iter: I,
133}
134
135impl<I> ComplementIter<I>
136where
137 I: Iterator,
138 I::Item: Complementable,
139{
140 pub fn new(iter: I) -> Self {
141 ComplementIter {
142 iter,
143 }
144 }
145}
146
147impl<I> Iterator for ComplementIter<I>
148where
149 I: Iterator,
150 I::Item: Complementable,
151{
152 type Item = ComplementResult<<I::Item as Complementable>::Output>;
153
154 fn next(&mut self) -> Option<Self::Item> {
155 Some(self.iter.next()?.complement())
156 }
157
158 fn size_hint(&self) -> (usize, Option<usize>) {
159 self.iter.size_hint()
160 }
161}
162
163impl<I> DoubleEndedIterator for ComplementIter<I>
164where
165 I: DoubleEndedIterator,
166 I::Item: Complementable,
167{
168 fn next_back(&mut self) -> Option<Self::Item> {
169 Some(self.iter.next_back()?.complement())
170 }
171}