Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions library/alloc/src/io/impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::boxed::Box;
use crate::io::SizeHint;

// =============================================================================
// Forwarding implementations

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl<T> SizeHint for Box<T> {
#[inline]
fn lower_bound(&self) -> usize {
SizeHint::lower_bound(&**self)
}

#[inline]
fn upper_bound(&self) -> Option<usize> {
SizeHint::upper_bound(&**self)
}
}

// =============================================================================
// In-memory buffer implementations
3 changes: 2 additions & 1 deletion library/alloc/src/io/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Traits, helpers, and type definitions for core I/O functionality.

mod error;
mod impls;

#[unstable(feature = "raw_os_error_ty", issue = "107792")]
pub use core::io::RawOsError;
Expand All @@ -17,4 +18,4 @@ pub use core::io::{
};
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub use core::io::{OsFunctions, chain, take};
pub use core::io::{IoHandle, OsFunctions, SizeHint, chain, take};
35 changes: 35 additions & 0 deletions library/core/src/io/impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::io::SizeHint;

// =============================================================================
// Forwarding implementations

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl<T> SizeHint for &mut T {
#[inline]
fn lower_bound(&self) -> usize {
SizeHint::lower_bound(*self)
}

#[inline]
fn upper_bound(&self) -> Option<usize> {
SizeHint::upper_bound(*self)
}
}

// =============================================================================
// In-memory buffer implementations

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl SizeHint for &[u8] {
#[inline]
fn lower_bound(&self) -> usize {
self.len()
}

#[inline]
fn upper_bound(&self) -> Option<usize> {
Some(self.len())
}
}
23 changes: 23 additions & 0 deletions library/core/src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
mod borrowed_buf;
mod cursor;
mod error;
mod impls;
mod io_slice;
mod size_hint;
mod util;

#[unstable(feature = "core_io_borrowed_buf", issue = "117693")]
Expand All @@ -25,5 +27,26 @@ pub use self::{
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub use self::{
error::{Custom, CustomOwner, OsFunctions},
size_hint::SizeHint,
util::{chain, take},
};

/// Marks that a type `T` can have IO traits such as [`Seek`], [`Write`], etc. automatically
/// implemented for handle types like [`Arc`][arc] as well.
///
/// This trait should only be implemented for types where `<&T as Trait>::method(&mut &value, ..)`
/// would be identical to `<T as Trait>::method(&mut value, ..)`.
///
/// [`File`][file] passes this test, as operations on `&File` and `File` both affect
/// the same underlying file.
/// `[u8]` fails, because any modification to `&mut &[u8]` would only affect a temporary
/// and be lost after the method has been called.
///
// FIXME(#74481): Hard-links required to link from `core` to `std`
/// [file]: ../../std/fs/struct.File.html
/// [arc]: ../../alloc/sync/struct.Arc.html
/// [`Write`]: ../../std/io/trait.Write.html
/// [`Seek`]: ../../std/io/trait.Seek.html
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub trait IoHandle {}
60 changes: 60 additions & 0 deletions library/core/src/io/size_hint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/// Internal trait used to allow for specialization in `Read::size_hint` and
/// `Iterator::size_hint`.
///
/// All types implement this through a blanket default implementation returning
/// a hint of `(0, None)`.
///
/// Implementors should only provide [`lower_bound`](SizeHint::lower_bound) and
/// [`upper_bound`](SizeHint::upper_bound).
/// [`size_hint`](SizeHint::size_hint) is provided as a `final` method to enforce
/// correctness.
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
pub trait SizeHint {
Comment thread
bushrat011899 marked this conversation as resolved.
/// Returns a lower bound on the number of elements this container-like item
/// contains.
/// For example, an array `[u8; 12]` could return any value between `0` and
/// `12` inclusively as a correct implementation.
///
/// Through specialization, all types implement this method returning a default
/// value of `0`.
///
/// Implementations *must* ensure the returned value is less than or equal to
/// the true element count.
fn lower_bound(&self) -> usize;

/// Returns an upper bound on the number of elements this container-like item
/// contains if it can be determined, otherwise `None`.
///
/// Through specialization, all types implement this method returning a default
/// value of `None`.
///
/// Implementations *must* ensure the returned value is greater than or equal
/// to the true element count.
fn upper_bound(&self) -> Option<usize>;

/// Returns an estimate for the number of elements this container like type
/// contains.
///
/// This is a `final` method, and is guaranteed to return
/// `(self.lower_bound(), self.upper_bound())`.
///
/// Without specialization, types implementing this trait will return `(0, None)`.
final fn size_hint(&self) -> (usize, Option<usize>) {
(self.lower_bound(), self.upper_bound())
}
}

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl<T: ?Sized> SizeHint for T {
#[inline]
default fn lower_bound(&self) -> usize {
0
}

#[inline]
default fn upper_bound(&self) -> Option<usize> {
None
}
}
60 changes: 59 additions & 1 deletion library/core/src/io/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::fmt;
use crate::io::SizeHint;
use crate::{cmp, fmt};

/// `Empty` ignores any data written via [`Write`], and will always be empty
/// (returning zero bytes) when read via [`Read`].
Expand All @@ -13,6 +14,15 @@ use crate::fmt;
#[derive(Copy, Clone, Debug, Default)]
pub struct Empty;

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl SizeHint for Empty {
#[inline]
fn upper_bound(&self) -> Option<usize> {
Some(0)
}
}

/// Creates a value that is always at EOF for reads, and ignores all data written.
///
/// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`]
Expand Down Expand Up @@ -63,6 +73,20 @@ pub struct Repeat {
pub byte: u8,
}

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl SizeHint for Repeat {
#[inline]
fn lower_bound(&self) -> usize {
usize::MAX
}

#[inline]
fn upper_bound(&self) -> Option<usize> {
None
}
}

/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
Expand Down Expand Up @@ -145,6 +169,23 @@ pub struct Chain<T, U> {
pub done_first: bool,
}

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl<T, U> SizeHint for Chain<T, U> {
#[inline]
fn lower_bound(&self) -> usize {
SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second)
}

#[inline]
fn upper_bound(&self) -> Option<usize> {
match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) {
(Some(first), Some(second)) => first.checked_add(second),
_ => None,
}
}
}

impl<T, U> Chain<T, U> {
/// Consumes the `Chain`, returning the wrapped readers.
///
Expand Down Expand Up @@ -253,6 +294,23 @@ pub struct Take<T> {
pub limit: u64,
}

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl<T> SizeHint for Take<T> {
#[inline]
fn lower_bound(&self) -> usize {
cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize
}

#[inline]
fn upper_bound(&self) -> Option<usize> {
match SizeHint::upper_bound(&self.inner) {
Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize),
None => self.limit.try_into().ok(),
}
}
}

impl<T> Take<T> {
/// Returns the number of bytes that can be read before this instance will
/// return EOF.
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,8 @@ impl Seek for File {
(&*self).stream_position()
}
}
#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl crate::io::IoHandle for File {}

impl Dir {
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/io/buffered/bufreader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,8 @@ impl<R: ?Sized + Seek> Seek for BufReader<R> {
}
}

#[doc(hidden)]
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
impl<T: ?Sized> SizeHint for BufReader<T> {
#[inline]
fn lower_bound(&self) -> usize {
Expand Down
Loading
Loading