1use core::iter::FusedIterator;
4
5use crate::Date;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct DateIter {
12 front: Date,
13 back: Option<Date>,
14}
15
16impl DateIter {
17 #[inline]
31 pub const fn new(start: Date, end: Date) -> Self {
32 Self {
33 front: start,
34 back: if start.as_i32() <= end.as_i32() {
35 Some(end)
36 } else {
37 None
38 },
39 }
40 }
41
42 #[inline]
44 const fn is_exhausted(&self) -> bool {
45 self.back.is_none()
46 }
47
48 #[inline]
50 const fn make_exhausted(&mut self) {
51 self.back = None;
52 }
53
54 #[inline]
57 const fn days_between(front: Date, back: Date) -> i32 {
58 if front.year() == back.year() {
59 back.ordinal() as i32 - front.ordinal() as i32
60 } else {
61 back.to_julian_day() - front.to_julian_day()
62 }
63 }
64}
65
66impl Iterator for DateIter {
67 type Item = Date;
68
69 #[inline]
70 fn next(&mut self) -> Option<Self::Item> {
71 let current = self.front;
72 let back = self.back?;
73
74 if current < back {
75 self.front = unsafe { current.next_day().unwrap_unchecked() };
77 } else {
78 self.make_exhausted();
79 }
80
81 Some(current)
82 }
83
84 #[inline]
85 fn size_hint(&self) -> (usize, Option<usize>) {
86 let len = self.len();
87 (len, Some(len))
88 }
89
90 #[inline]
91 fn count(self) -> usize {
92 self.len()
93 }
94
95 #[inline]
96 fn last(self) -> Option<Self::Item> {
97 self.back
98 }
99
100 #[inline]
101 fn nth(&mut self, n: usize) -> Option<Self::Item> {
102 let back = self.back?;
103 let front = self.front;
104
105 let same_year = front.year() == back.year();
106 let remaining = if same_year {
107 (back.ordinal() - front.ordinal()) as usize
108 } else {
109 (back.to_julian_day() - front.to_julian_day()) as usize
110 };
111
112 if n > remaining {
113 self.make_exhausted();
114 return None;
115 }
116
117 let result = if same_year
120 || front.ordinal() as usize <= if front.is_in_leap_year() { 366 } else { 365 } - n
121 {
122 unsafe { front.add_days_unchecked(n as i32) }
125 } else {
126 unsafe { Date::from_julian_day_unchecked(front.to_julian_day() + n as i32) }
128 };
129
130 if n == remaining {
131 self.make_exhausted();
132 } else {
133 self.front = unsafe { result.next_day().unwrap_unchecked() };
135 }
136
137 Some(result)
138 }
139
140 #[inline]
141 fn max(self) -> Option<Self::Item> {
142 self.back
143 }
144
145 #[inline]
146 fn min(self) -> Option<Self::Item> {
147 (!self.is_exhausted()).then_some(self.front)
148 }
149
150 #[inline]
151 fn is_sorted(self) -> bool {
152 true
153 }
154}
155
156impl DoubleEndedIterator for DateIter {
157 #[inline]
158 fn next_back(&mut self) -> Option<Self::Item> {
159 let back = self.back?;
160
161 if self.front < back {
162 self.back = Some(unsafe { back.previous_day().unwrap_unchecked() });
164 } else {
165 self.make_exhausted();
166 }
167
168 Some(back)
169 }
170
171 #[inline]
172 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
173 let back = self.back?;
174 let front = self.front;
175
176 let same_year = front.year() == back.year();
177 let remaining = if same_year {
178 (back.ordinal() - front.ordinal()) as usize
179 } else {
180 (back.to_julian_day() - front.to_julian_day()) as usize
181 };
182
183 if n > remaining {
184 self.make_exhausted();
185 return None;
186 }
187
188 let result = if same_year || back.ordinal() as usize > n {
189 unsafe { back.add_days_unchecked(-(n as i32)) }
191 } else {
192 unsafe { Date::from_julian_day_unchecked(back.to_julian_day() - n as i32) }
194 };
195
196 if n == remaining {
197 self.make_exhausted();
198 } else {
199 self.back = Some(unsafe { result.previous_day().unwrap_unchecked() });
201 }
202
203 Some(result)
204 }
205}
206
207impl ExactSizeIterator for DateIter {
208 #[inline]
209 fn len(&self) -> usize {
210 let Some(back) = self.back else {
211 return 0;
212 };
213
214 Self::days_between(self.front, back) as usize + 1
215 }
216}
217
218impl FusedIterator for DateIter {}