use core::iter::FusedIterator;
use crate::Date;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DateIter {
front: Date,
back: Option<Date>,
}
impl DateIter {
#[inline]
pub const fn new(start: Date, end: Date) -> Self {
Self {
front: start,
back: if start.as_i32() <= end.as_i32() {
Some(end)
} else {
None
},
}
}
#[inline]
const fn is_exhausted(&self) -> bool {
self.back.is_none()
}
#[inline]
const fn make_exhausted(&mut self) {
self.back = None;
}
#[inline]
const fn days_between(front: Date, back: Date) -> i32 {
if front.year() == back.year() {
back.ordinal() as i32 - front.ordinal() as i32
} else {
back.to_julian_day() - front.to_julian_day()
}
}
}
impl Iterator for DateIter {
type Item = Date;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let current = self.front;
let back = self.back?;
if current < back {
self.front = unsafe { current.next_day().unwrap_unchecked() };
} else {
self.make_exhausted();
}
Some(current)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
#[inline]
fn count(self) -> usize {
self.len()
}
#[inline]
fn last(self) -> Option<Self::Item> {
self.back
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
let back = self.back?;
let front = self.front;
let same_year = front.year() == back.year();
let remaining = if same_year {
(back.ordinal() - front.ordinal()) as usize
} else {
(back.to_julian_day() - front.to_julian_day()) as usize
};
if n > remaining {
self.make_exhausted();
return None;
}
let result = if same_year
|| front.ordinal() as usize <= if front.is_in_leap_year() { 366 } else { 365 } - n
{
unsafe { front.add_days_unchecked(n as i32) }
} else {
unsafe { Date::from_julian_day_unchecked(front.to_julian_day() + n as i32) }
};
if n == remaining {
self.make_exhausted();
} else {
self.front = unsafe { result.next_day().unwrap_unchecked() };
}
Some(result)
}
#[inline]
fn max(self) -> Option<Self::Item> {
self.back
}
#[inline]
fn min(self) -> Option<Self::Item> {
(!self.is_exhausted()).then_some(self.front)
}
#[inline]
fn is_sorted(self) -> bool {
true
}
}
impl DoubleEndedIterator for DateIter {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let back = self.back?;
if self.front < back {
self.back = Some(unsafe { back.previous_day().unwrap_unchecked() });
} else {
self.make_exhausted();
}
Some(back)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
let back = self.back?;
let front = self.front;
let same_year = front.year() == back.year();
let remaining = if same_year {
(back.ordinal() - front.ordinal()) as usize
} else {
(back.to_julian_day() - front.to_julian_day()) as usize
};
if n > remaining {
self.make_exhausted();
return None;
}
let result = if same_year || back.ordinal() as usize > n {
unsafe { back.add_days_unchecked(-(n as i32)) }
} else {
unsafe { Date::from_julian_day_unchecked(back.to_julian_day() - n as i32) }
};
if n == remaining {
self.make_exhausted();
} else {
self.back = Some(unsafe { result.previous_day().unwrap_unchecked() });
}
Some(result)
}
}
impl ExactSizeIterator for DateIter {
#[inline]
fn len(&self) -> usize {
let Some(back) = self.back else {
return 0;
};
Self::days_between(self.front, back) as usize + 1
}
}
impl FusedIterator for DateIter {}