Skip to content

Commit 2460adc

Browse files
committed
Add Read::size_snapshot
1 parent bb1bd88 commit 2460adc

File tree

5 files changed

+90
-0
lines changed

5 files changed

+90
-0
lines changed

src/libstd/fs.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,19 @@ impl Read for File {
449449
self.inner.read(buf)
450450
}
451451

452+
fn size_snapshot(&self) -> Option<usize> {
453+
if let Ok(meta) = self.metadata() {
454+
let len = meta.len();
455+
let size = len as usize;
456+
// Don't trust a length of zero. For example, "pseudofiles" on Linux
457+
// like /proc/meminfo report a size of 0.
458+
if size != 0 && size as u64 == len {
459+
return Some(size);
460+
}
461+
}
462+
None
463+
}
464+
452465
#[inline]
453466
unsafe fn initializer(&self) -> Initializer {
454467
Initializer::nop()
@@ -473,6 +486,10 @@ impl<'a> Read for &'a File {
473486
self.inner.read(buf)
474487
}
475488

489+
fn size_snapshot(&self) -> Option<usize> {
490+
(**self).size_snapshot()
491+
}
492+
476493
#[inline]
477494
unsafe fn initializer(&self) -> Initializer {
478495
Initializer::nop()

src/libstd/io/buffered.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,15 @@ impl<R: Read> Read for BufReader<R> {
211211
Ok(nread)
212212
}
213213

214+
#[inline]
215+
fn size_snapshot(&self) -> Option<usize> {
216+
let buffered_len = self.cap - self.pos;
217+
if let Some(size) = self.inner.size_snapshot() {
218+
return buffered_len.checked_add(size);
219+
}
220+
None
221+
}
222+
214223
// we can't skip unconditionally because of the large buffer case in read.
215224
unsafe fn initializer(&self) -> Initializer {
216225
self.inner.initializer()

src/libstd/io/cursor.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,16 @@ impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
237237
Ok(())
238238
}
239239

240+
fn size_snapshot(&self) -> Option<usize> {
241+
if let Some(diff) = (self.inner.as_ref().len() as u64).checked_sub(self.pos) {
242+
let size = diff as usize;
243+
if size as u64 == diff {
244+
return Some(size);
245+
}
246+
}
247+
None
248+
}
249+
240250
#[inline]
241251
unsafe fn initializer(&self) -> Initializer {
242252
Initializer::nop()

src/libstd/io/impls.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R {
2323
(**self).read(buf)
2424
}
2525

26+
#[inline]
27+
fn size_snapshot(&self) -> Option<usize> {
28+
(**self).size_snapshot()
29+
}
30+
2631
#[inline]
2732
unsafe fn initializer(&self) -> Initializer {
2833
(**self).initializer()
@@ -92,6 +97,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
9297
(**self).read(buf)
9398
}
9499

100+
#[inline]
101+
fn size_snapshot(&self) -> Option<usize> {
102+
(**self).size_snapshot()
103+
}
104+
95105
#[inline]
96106
unsafe fn initializer(&self) -> Initializer {
97107
(**self).initializer()
@@ -181,6 +191,11 @@ impl<'a> Read for &'a [u8] {
181191
Ok(amt)
182192
}
183193

194+
#[inline]
195+
fn size_snapshot(&self) -> Option<usize> {
196+
Some(self.len())
197+
}
198+
184199
#[inline]
185200
unsafe fn initializer(&self) -> Initializer {
186201
Initializer::nop()

src/libstd/io/mod.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,21 @@ pub trait Read {
553553
Initializer::zeroing()
554554
}
555555

556+
/// Return a snapshot of how many bytes would be read from this source until EOF
557+
/// if read immediately, or None if that is unknown. Depending on the source, the
558+
/// size may change at any time, so this isn't a guarantee that exactly that number
559+
/// of bytes will actually be read.
560+
///
561+
/// This is used by [`read_to_end`] and [`read_to_string`] to pre-allocate a memory buffer.
562+
///
563+
/// [`read_to_end`]: #method.read_to_end
564+
/// [`read_to_string`]: #method.read_to_string
565+
#[unstable(feature = "read_size_snapshot", issue = /* FIXME */ "0")]
566+
#[inline]
567+
fn size_snapshot(&self) -> Option<usize> {
568+
None
569+
}
570+
556571
/// Read all bytes until EOF in this source, placing them into `buf`.
557572
///
558573
/// All bytes read from this source will be appended to the specified buffer
@@ -1729,6 +1744,19 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
17291744
self.second.read(buf)
17301745
}
17311746

1747+
fn size_snapshot(&self) -> Option<usize> {
1748+
if self.done_first {
1749+
self.second.size_snapshot()
1750+
} else {
1751+
if let Some(second_size) = self.second.size_snapshot() {
1752+
if let Some(first_size) = self.first.size_snapshot() {
1753+
return first_size.checked_add(second_size);
1754+
}
1755+
}
1756+
None
1757+
}
1758+
}
1759+
17321760
unsafe fn initializer(&self) -> Initializer {
17331761
let initializer = self.first.initializer();
17341762
if initializer.should_initialize() {
@@ -1927,6 +1955,17 @@ impl<T: Read> Read for Take<T> {
19271955
Ok(n)
19281956
}
19291957

1958+
fn size_snapshot(&self) -> Option<usize> {
1959+
if let Some(inner_size) = self.inner.size_snapshot() {
1960+
let min = cmp::min(self.limit, inner_size as u64);
1961+
let size = min as usize;
1962+
if size as u64 == min {
1963+
return Some(size);
1964+
}
1965+
}
1966+
None
1967+
}
1968+
19301969
unsafe fn initializer(&self) -> Initializer {
19311970
self.inner.initializer()
19321971
}

0 commit comments

Comments
 (0)