Skip to content

Commit b7dd942

Browse files
authored
Rollup merge of rust-lang#86202 - a1phyr:spec_io_bytes_size_hint, r=m-ou-se
Specialize `io::Bytes::size_hint` for more types Improve the result of `<io::Bytes as Iterator>::size_hint` for some readers. I did not manage to specialize `SizeHint` for `io::Cursor` Side question: would it be interesting for `io::Read` to have an optional `size_hint` method ?
2 parents fcac478 + 2cbd5d1 commit b7dd942

File tree

4 files changed

+96
-3
lines changed

4 files changed

+96
-3
lines changed

library/std/src/io/buffered/bufreader.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,13 @@ impl<R: Seek> Seek for BufReader<R> {
438438
}
439439

440440
impl<T> SizeHint for BufReader<T> {
441+
#[inline]
441442
fn lower_bound(&self) -> usize {
442-
self.buffer().len()
443+
SizeHint::lower_bound(self.get_ref()) + self.buffer().len()
444+
}
445+
446+
#[inline]
447+
fn upper_bound(&self) -> Option<usize> {
448+
SizeHint::upper_bound(self.get_ref()).and_then(|up| self.buffer().len().checked_add(up))
443449
}
444450
}

library/std/src/io/mod.rs

+57-1
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@
252252
mod tests;
253253

254254
use crate::cmp;
255+
use crate::convert::TryInto;
255256
use crate::fmt;
256257
use crate::mem::replace;
257258
use crate::ops::{Deref, DerefMut};
@@ -2342,13 +2343,15 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
23422343
}
23432344

23442345
impl<T, U> SizeHint for Chain<T, U> {
2346+
#[inline]
23452347
fn lower_bound(&self) -> usize {
23462348
SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second)
23472349
}
23482350

2351+
#[inline]
23492352
fn upper_bound(&self) -> Option<usize> {
23502353
match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) {
2351-
(Some(first), Some(second)) => Some(first + second),
2354+
(Some(first), Some(second)) => first.checked_add(second),
23522355
_ => None,
23532356
}
23542357
}
@@ -2553,6 +2556,21 @@ impl<T: BufRead> BufRead for Take<T> {
25532556
}
25542557
}
25552558

2559+
impl<T> SizeHint for Take<T> {
2560+
#[inline]
2561+
fn lower_bound(&self) -> usize {
2562+
cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize
2563+
}
2564+
2565+
#[inline]
2566+
fn upper_bound(&self) -> Option<usize> {
2567+
match SizeHint::upper_bound(&self.inner) {
2568+
Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize),
2569+
None => self.limit.try_into().ok(),
2570+
}
2571+
}
2572+
}
2573+
25562574
/// An iterator over `u8` values of a reader.
25572575
///
25582576
/// This struct is generally created by calling [`bytes`] on a reader.
@@ -2597,15 +2615,53 @@ trait SizeHint {
25972615
}
25982616

25992617
impl<T> SizeHint for T {
2618+
#[inline]
26002619
default fn lower_bound(&self) -> usize {
26012620
0
26022621
}
26032622

2623+
#[inline]
26042624
default fn upper_bound(&self) -> Option<usize> {
26052625
None
26062626
}
26072627
}
26082628

2629+
impl<T> SizeHint for &mut T {
2630+
#[inline]
2631+
fn lower_bound(&self) -> usize {
2632+
SizeHint::lower_bound(*self)
2633+
}
2634+
2635+
#[inline]
2636+
fn upper_bound(&self) -> Option<usize> {
2637+
SizeHint::upper_bound(*self)
2638+
}
2639+
}
2640+
2641+
impl<T> SizeHint for Box<T> {
2642+
#[inline]
2643+
fn lower_bound(&self) -> usize {
2644+
SizeHint::lower_bound(&**self)
2645+
}
2646+
2647+
#[inline]
2648+
fn upper_bound(&self) -> Option<usize> {
2649+
SizeHint::upper_bound(&**self)
2650+
}
2651+
}
2652+
2653+
impl SizeHint for &[u8] {
2654+
#[inline]
2655+
fn lower_bound(&self) -> usize {
2656+
self.len()
2657+
}
2658+
2659+
#[inline]
2660+
fn upper_bound(&self) -> Option<usize> {
2661+
Some(self.len())
2662+
}
2663+
}
2664+
26092665
/// An iterator over the contents of an instance of `BufRead` split on a
26102666
/// particular byte.
26112667
///

library/std/src/io/tests.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,24 @@ fn empty_size_hint() {
224224
assert_eq!(size_hint, (0, Some(0)));
225225
}
226226

227+
#[test]
228+
fn slice_size_hint() {
229+
let size_hint = (&[1, 2, 3]).bytes().size_hint();
230+
assert_eq!(size_hint, (3, Some(3)));
231+
}
232+
233+
#[test]
234+
fn take_size_hint() {
235+
let size_hint = (&[1, 2, 3]).take(2).bytes().size_hint();
236+
assert_eq!(size_hint, (2, Some(2)));
237+
238+
let size_hint = (&[1, 2, 3]).take(4).bytes().size_hint();
239+
assert_eq!(size_hint, (3, Some(3)));
240+
241+
let size_hint = io::repeat(0).take(3).bytes().size_hint();
242+
assert_eq!(size_hint, (3, Some(3)));
243+
}
244+
227245
#[test]
228246
fn chain_empty_size_hint() {
229247
let chain = io::empty().chain(io::empty());
@@ -242,7 +260,7 @@ fn chain_size_hint() {
242260

243261
let chain = buf_reader_1.chain(buf_reader_2);
244262
let size_hint = chain.bytes().size_hint();
245-
assert_eq!(size_hint, (testdata.len(), None));
263+
assert_eq!(size_hint, (testdata.len(), Some(testdata.len())));
246264
}
247265

248266
#[test]

library/std/src/io/util.rs

+13
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ impl fmt::Debug for Empty {
8383
}
8484

8585
impl SizeHint for Empty {
86+
#[inline]
8687
fn upper_bound(&self) -> Option<usize> {
8788
Some(0)
8889
}
@@ -147,6 +148,18 @@ impl Read for Repeat {
147148
}
148149
}
149150

151+
impl SizeHint for Repeat {
152+
#[inline]
153+
fn lower_bound(&self) -> usize {
154+
usize::MAX
155+
}
156+
157+
#[inline]
158+
fn upper_bound(&self) -> Option<usize> {
159+
None
160+
}
161+
}
162+
150163
#[stable(feature = "std_debug", since = "1.16.0")]
151164
impl fmt::Debug for Repeat {
152165
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

0 commit comments

Comments
 (0)