1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
use core::iter::FusedIterator;
use crate::HintSize;
#[cfg(doc)]
use crate::*;
/// Extension trait for [`Iterator`] and [`FusedIterator`] to create iterators with custom
/// [`Iterator::size_hint`] and/or [`ExactSizeIterator::len`] implementations.
pub trait SizeHinter: Iterator + Sized {
/// Wraps this [`FusedIterator`] in a [`HintSize`] that produces a [`SizeHint`] based on
/// `lower` and `upper`.
///
/// This is most useful for testing, but can also enable optimizations if a more accurate
/// [`SizeHint`] is available. Prefer [`Self::exact_len`] if the exact number of elements is known.
/// This adaptor can also prevent optimizations if the iterator already implements `TrustedLen`.
///
/// It is the caller's responsibility to ensure that `lower` and `upper` are accurate bounds
/// for the number of elements remaining in this iterator. Incorrect values may cause errors or
/// panics in code that relies on this [`Iterator::size_hint`].
///
/// # Panics
///
/// Panics if:
/// - `lower > upper`
/// - `upper` is less than this [`Iterator::size_hint`]'s lower bound
/// - `lower` is greater than this [`Iterator::size_hint`]'s upper bound (if present)
///
/// # Examples
///
/// ```rust
/// use size_hinter::SizeHinter;
///
/// let mut iter = (1..5).hint_size(2, 6);
///
/// assert_eq!(iter.size_hint(), (2, Some(6)), "Should match initial size hint");
/// assert_eq!(iter.next(), Some(1), "Should not change underlying iterator");
/// assert_eq!(iter.size_hint(), (1, Some(5)), "Should reflect new state");
/// ```
#[inline]
fn hint_size(self, lower: usize, upper: usize) -> HintSize<Self>
where
Self: FusedIterator,
{
HintSize::new(self, lower, upper)
}
/// Wraps this [`Iterator`] in a [`HintSize`] that produces a [`SizeHint`] based on `lower`.
///
/// This is useful for testing, but can also enable optimizations if a more accurate lower
/// bound is known for this iterator. This adaptor can also prevent optimizations if this
/// iterator already implements `TrustedLen`.
///
/// It is the caller's responsibility to ensure that `lower` is an accurate lower bound for the
/// number of elements remaining in this iterator. An incorrect value may cause errors or
/// panics in code that relies on this [`Iterator::size_hint`].
///
/// # Panics
///
/// Panics if `lower` is greater than the upper bound of this [`Iterator::size_hint`] (if present).
///
/// # Examples
///
/// ```rust
/// use size_hinter::SizeHinter;
///
/// let mut iter = (1..5).hint_min(4);
///
/// assert_eq!(iter.size_hint(), (4, None), "Should match initial lower bound");
/// assert_eq!(iter.next(), Some(1), "Should not change underlying iterator");
/// assert_eq!(iter.size_hint(), (3, None), "Should reflect new lower bound");
/// ```
#[inline]
fn hint_min(self, lower: usize) -> HintSize<Self> {
HintSize::min(self, lower)
}
/// Tries to wrap this [`FusedIterator`] in a [`HintSize`] that produces a [`SizeHint`] based on
/// `lower` and `upper`.
///
/// See [`Self::hint_size`] for more details.
///
/// # Errors
///
/// Returns an [`InvalidSizeHint`] if:
/// - `lower > upper`
/// - `upper` is less than this [`Iterator::size_hint`]'s lower bound
/// - `lower` is greater than this [`Iterator::size_hint`]'s upper bound (if present)
///
/// # Panics
///
/// Panics if the wrapped iterator's [`Iterator::size_hint`] is invalid.
///
/// # Examples
///
/// ```rust
/// # use size_hinter::{SizeHinter, InvalidSizeHint};
/// # fn main() -> Result<(), InvalidSizeHint> {
/// let mut iter = (1..5).try_hint_size(2, 6)?;
/// assert_eq!(iter.size_hint(), (2, Some(6)), "Should match initial size hint");
/// assert_eq!(iter.next(), Some(1), "Should not change underlying iterator");
/// assert_eq!(iter.size_hint(), (1, Some(5)), "Should reflect new state");
///
/// let err: InvalidSizeHint = (10..20).try_hint_size(15, 5)
/// .expect_err("Lower bound should not be greater than upper bound");
/// # Ok(())
/// # }
/// ```
#[inline]
fn try_hint_size(self, lower: usize, upper: usize) -> Result<HintSize<Self>, crate::InvalidSizeHint>
where
Self: FusedIterator,
{
HintSize::try_new(self, lower, upper)
}
/// Tries to wrap this [`Iterator`] in a [`HintSize`] that produces a [`SizeHint`] based on `lower`.
///
/// See [`Self::hint_min`] for more details.
///
/// # Errors
///
/// Returns an [`InvalidSizeHint`] if `lower` is greater than the upper bound of this
/// [`Iterator::size_hint`] (if present).
///
/// # Panics
///
/// Panics if the wrapped iterator's [`Iterator::size_hint`] is invalid.
///
/// # Examples
///
/// ```rust
/// # use size_hinter::{SizeHinter, InvalidSizeHint};
/// # fn main() -> Result<(), InvalidSizeHint> {
/// let mut iter = (1..5).try_hint_min(4)?;
/// assert_eq!(iter.size_hint(), (4, None), "Should match initial lower bound");
/// assert_eq!(iter.next(), Some(1), "Should not change underlying iterator");
/// assert_eq!(iter.size_hint(), (3, None), "Should reflect new lower bound");
///
/// let err: InvalidSizeHint = (10..20).try_hint_min(25)
/// .expect_err("Lower bound should not be greater than upper bound");
/// # Ok(())
/// # }
/// ```
#[inline]
fn try_hint_min(self, lower: usize) -> Result<HintSize<Self>, crate::InvalidSizeHint> {
HintSize::try_min(self, lower)
}
/// Wraps this [`Iterator`] in a [`HintSize`] that produces a [`SizeHint::UNIVERSAL`].
///
/// This implementation, and the [`SizeHint::UNIVERSAL`] it returns, is always correct,
/// and never changes. It is most useful for testing.
///
/// # Examples
///
/// ```rust
/// use size_hinter::SizeHinter;
///
/// let mut iter = (1..5).hide_size();
///
/// assert_eq!(iter.size_hint(), (0, None), "Should match universal size hint");
/// assert_eq!(iter.next(), Some(1), "Should not change underlying iterator");
/// assert_eq!(iter.size_hint(), (0, None), "Should still match universal size hint");
/// ```
#[inline]
fn hide_size(self) -> HintSize<Self> {
HintSize::hide(self)
}
/// Wraps this [`FusedIterator`] in a [`ExactLen`] that provides [`ExactSizeIterator::len`]
/// based on `len`.
///
/// This is useful for iterators that don't normally implement [`ExactSizeIterator`] but for
/// which the exact number of elements the iterator will yield is known. This may allow
/// performance optimizations. However it may also prevent optimizations if the wrapped
/// iterator already implements `TrustedLen`, even if it does not implement
/// [`ExactSizeIterator`]. For example, [`Chain`](core::iter::Chain).
///
/// [`ExactLen`] also produces a corresponding [`SizeHint`] based on `len`.
///
/// It is the caller's responsibility to ensure that `len` accurately represents the number of
/// elements remaining in this iterator. An incorrect value may cause errors or panics in code
/// that relies on [`ExactSizeIterator::len`].
///
/// # Panics
///
/// Panics if:
/// - the wrapped [`Iterator::size_hint`] is invalid
/// - `len` is less than the wrapped [`Iterator::size_hint`]'s lower bound
/// - `len` is greater than the wrapped [`Iterator::size_hint`]'s upper bound (if present)
///
/// # Examples
///
/// ```
/// use size_hinter::SizeHinter;
///
/// let mut iter = (1..5).exact_len(4);
///
/// assert_eq!(iter.len(), 4, "Length should match len");
/// assert_eq!(iter.size_hint(), (4, Some(4)), "Size hint should match len");
///
/// assert_eq!(iter.next(), Some(1), "Should not change underlying iterator");
/// assert_eq!(iter.len(), 3, "Length should match new len");
/// assert_eq!(iter.size_hint(), (3, Some(3)), "Size hint should match new len");
/// ```
#[inline]
fn exact_len(self, len: usize) -> crate::ExactLen<Self>
where
Self: FusedIterator,
{
crate::ExactLen::new(self, len)
}
/// Tries to wrap this [`FusedIterator`] in a [`ExactLen`] that provides [`ExactSizeIterator::len`]
/// based on `len`.
///
/// See [`Self::exact_len`] for more details.
///
/// # Errors
///
/// Returns an [`InvalidSizeHint`] if the wrapped iterator's size hint does not contain `len`.
///
/// # Panics
///
/// Panics if the wrapped iterator's [`Iterator::size_hint`] is invalid.
///
/// # Examples
///
/// ```
/// # use size_hinter::{SizeHinter, InvalidSizeHint};
/// # fn main() -> Result<(), InvalidSizeHint> {
/// let mut iter = (1..=5).filter(|&x| x % 2 == 0).try_exact_len(3)?;
/// assert_eq!(iter.len(), 3, "Length should match len");
/// assert_eq!(iter.size_hint(), (3, Some(3)), "Size hint should match len");
///
/// let err: InvalidSizeHint = (10..20).try_exact_len(15)
/// .expect_err("Len should not be within wrapped iterator size hint");
/// # Ok(())
/// # }
/// ```
#[inline]
fn try_exact_len(self, len: usize) -> Result<crate::ExactLen<Self>, crate::InvalidSizeHint>
where
Self: FusedIterator,
{
crate::ExactLen::try_new(self, len)
}
}
impl<I: Iterator> SizeHinter for I {}