use std::cmp::Ordering;
use std::iter::{FusedIterator, Peekable};
use crate::intervals::absolute::{AbsBound, AbsEndBound};
use crate::intervals::ops::BoundOrd;
use crate::intervals::ops::bound_overlap_ambiguity::BoundOverlapDisambiguationRuleSet;
use crate::intervals::relative::{RelBound, RelEndBound};
use crate::iter::intervals::layered_bounds::{LayeredAbsBounds, LayeredRelBounds};
pub struct AbsUnitedBoundsIter<I> {
iter: I,
layer: u64,
is_next_start_adjacent: bool,
exhausted: bool,
}
impl<I> AbsUnitedBoundsIter<I>
where
I: Iterator<Item = AbsBound>,
{
#[must_use]
pub fn new(iter: I) -> AbsUnitedBoundsIter<Peekable<I>> {
AbsUnitedBoundsIter {
iter: iter.peekable(),
layer: 0,
is_next_start_adjacent: false,
exhausted: false,
}
}
}
impl<I> AbsUnitedBoundsIter<Peekable<I>>
where
I: Iterator<Item = AbsBound>,
{
pub fn layer<J>(
self,
second_layer: AbsUnitedBoundsIter<Peekable<J>>,
) -> LayeredAbsBounds<Peekable<Self>, Peekable<AbsUnitedBoundsIter<Peekable<J>>>>
where
J: Iterator<Item = AbsBound>,
{
LayeredAbsBounds::new(self, second_layer)
}
}
impl<I> Iterator for AbsUnitedBoundsIter<Peekable<I>>
where
I: Iterator<Item = AbsBound>,
{
type Item = AbsBound;
fn next(&mut self) -> Option<Self::Item> {
if self.exhausted {
return None;
}
loop {
let Some(next) = self.iter.next() else {
self.exhausted = true;
return None;
};
match next {
AbsBound::Start(_) => {
self.layer = self
.layer
.checked_add(1)
.expect("The number of active layers overflowed when using `AbsUniteBoundsIter`");
if self.is_next_start_adjacent {
self.is_next_start_adjacent = false;
continue;
}
if self.layer > 1 {
continue;
}
},
AbsBound::End(next_end) => {
self.layer = self.layer.checked_sub(1).expect(
"An error occurred with `AbsUniteBoundsIter`: The number of active layers underflowed, which \
is unexpected",
);
if self.layer > 0 {
continue;
}
if self
.iter
.peek()
.is_some_and(|peeked| is_abs_end_bound_adjacent_to_abs_peeked(&next_end, peeked))
{
self.is_next_start_adjacent = true;
continue;
}
},
}
return Some(next);
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let inner_size_hint = self.iter.size_hint();
(
inner_size_hint.0.saturating_mul(2),
inner_size_hint.1.and_then(|x| x.checked_mul(2)),
)
}
}
impl<I> FusedIterator for AbsUnitedBoundsIter<Peekable<I>> where I: Iterator<Item = AbsBound> {}
fn is_abs_end_bound_adjacent_to_abs_peeked(end: &AbsEndBound, peeked: &AbsBound) -> bool {
let AbsBound::Start(peeked_start) = peeked else {
return false;
};
matches!(
end.bound_cmp(peeked_start)
.disambiguate(BoundOverlapDisambiguationRuleSet::Lenient),
Ordering::Equal,
)
}
pub struct RelUnitedBoundsIter<I> {
iter: I,
layer: u64,
is_next_start_adjacent: bool,
exhausted: bool,
}
impl<I> RelUnitedBoundsIter<I>
where
I: Iterator<Item = RelBound>,
{
#[must_use]
pub fn new(iter: I) -> RelUnitedBoundsIter<Peekable<I>> {
RelUnitedBoundsIter {
iter: iter.peekable(),
layer: 0,
is_next_start_adjacent: false,
exhausted: false,
}
}
}
impl<I> RelUnitedBoundsIter<Peekable<I>>
where
I: Iterator<Item = RelBound>,
{
pub fn layer<J>(
self,
second_layer: RelUnitedBoundsIter<Peekable<J>>,
) -> LayeredRelBounds<Peekable<Self>, Peekable<RelUnitedBoundsIter<Peekable<J>>>>
where
J: Iterator<Item = RelBound>,
{
LayeredRelBounds::new(self, second_layer)
}
}
impl<I> Iterator for RelUnitedBoundsIter<Peekable<I>>
where
I: Iterator<Item = RelBound>,
{
type Item = RelBound;
fn next(&mut self) -> Option<Self::Item> {
if self.exhausted {
return None;
}
loop {
let Some(next) = self.iter.next() else {
self.exhausted = true;
return None;
};
match next {
RelBound::Start(_) => {
self.layer = self
.layer
.checked_add(1)
.expect("The number of active layers overflowed when using `RelUniteBoundsIter`");
if self.is_next_start_adjacent {
self.is_next_start_adjacent = false;
continue;
}
if self.layer > 1 {
continue;
}
},
RelBound::End(next_end) => {
self.layer = self.layer.checked_sub(1).expect(
"An error occurred with `RelUniteBoundsIter`: The number of active layers underflowed, which \
is unexpected",
);
if self.layer > 0 {
continue;
}
if self
.iter
.peek()
.is_some_and(|peeked| is_rel_end_bound_adjacent_to_rel_peeked(&next_end, peeked))
{
self.is_next_start_adjacent = true;
continue;
}
},
}
return Some(next);
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let inner_size_hint = self.iter.size_hint();
(
inner_size_hint.0.saturating_mul(2),
inner_size_hint.1.and_then(|x| x.checked_mul(2)),
)
}
}
impl<I> FusedIterator for RelUnitedBoundsIter<Peekable<I>> where I: Iterator<Item = RelBound> {}
fn is_rel_end_bound_adjacent_to_rel_peeked(end: &RelEndBound, peeked: &RelBound) -> bool {
let RelBound::Start(peeked_start) = peeked else {
return false;
};
matches!(
end.bound_cmp(peeked_start)
.disambiguate(BoundOverlapDisambiguationRuleSet::Lenient),
Ordering::Equal,
)
}