Skip to content

Commit 1819408

Browse files
yoshuawuytsStjepan Glavina
authored and
Stjepan Glavina
committed
add stream::ExactSizeStream as unstable (#330)
Signed-off-by: Yoshua Wuyts <[email protected]>
1 parent 6be8467 commit 1819408

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

src/prelude.rs

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
//! use async_std::prelude::*;
1212
//! ```
1313
14+
use cfg_if::cfg_if;
15+
1416
#[doc(no_inline)]
1517
pub use crate::future::Future;
1618
#[doc(no_inline)]
@@ -36,3 +38,13 @@ pub use crate::io::seek::SeekExt as _;
3638
pub use crate::io::write::WriteExt as _;
3739
#[doc(hidden)]
3840
pub use crate::stream::stream::StreamExt as _;
41+
42+
cfg_if! {
43+
if #[cfg(any(feature = "unstable", feature = "docs"))] {
44+
#[doc(no_inline)]
45+
pub use crate::stream::DoubleEndedStream;
46+
47+
#[doc(no_inline)]
48+
pub use crate::stream::ExactSizeStream;
49+
}
50+
}

src/stream/exact_size_stream.rs

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
pub use crate::stream::Stream;
2+
3+
/// A stream that knows its exact length.
4+
///
5+
/// Many [`Stream`]s don't know how many times they will iterate, but some do.
6+
/// If a stream knows how many times it can iterate, providing access to
7+
/// that information can be useful. For example, if you want to iterate
8+
/// backwards, a good start is to know where the end is.
9+
///
10+
/// When implementing an `ExactSizeStream`, you must also implement
11+
/// [`Stream`]. When doing so, the implementation of [`size_hint`] *must*
12+
/// return the exact size of the stream.
13+
///
14+
/// [`Stream`]: trait.Stream.html
15+
/// [`size_hint`]: trait.Stream.html#method.size_hint
16+
///
17+
/// The [`len`] method has a default implementation, so you usually shouldn't
18+
/// implement it. However, you may be able to provide a more performant
19+
/// implementation than the default, so overriding it in this case makes sense.
20+
///
21+
/// [`len`]: #method.len
22+
///
23+
/// # Examples
24+
///
25+
/// Basic usage:
26+
///
27+
/// ```
28+
/// // a finite range knows exactly how many times it will iterate
29+
/// let five = 0..5;
30+
///
31+
/// assert_eq!(5, five.len());
32+
/// ```
33+
///
34+
/// In the [module level docs][moddocs], we implemented an [`Stream`],
35+
/// `Counter`. Let's implement `ExactSizeStream` for it as well:
36+
///
37+
/// [moddocs]: index.html
38+
///
39+
/// ```
40+
/// # use std::task::{Context, Poll};
41+
/// # use std::pin::Pin;
42+
/// # use async_std::prelude::*;
43+
/// # struct Counter {
44+
/// # count: usize,
45+
/// # }
46+
/// # impl Counter {
47+
/// # fn new() -> Counter {
48+
/// # Counter { count: 0 }
49+
/// # }
50+
/// # }
51+
/// # impl Stream for Counter {
52+
/// # type Item = usize;
53+
/// # fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
54+
/// # self.count += 1;
55+
/// # if self.count < 6 {
56+
/// # Poll::Ready(Some(self.count))
57+
/// # } else {
58+
/// # Poll::Ready(None)
59+
/// # }
60+
/// # }
61+
/// # }
62+
/// # fn main() { async_std::task::block_on(async {
63+
/// #
64+
/// impl ExactSizeStream for Counter {
65+
/// // We can easily calculate the remaining number of iterations.
66+
/// fn len(&self) -> usize {
67+
/// 5 - self.count
68+
/// }
69+
/// }
70+
///
71+
/// // And now we can use it!
72+
///
73+
/// let counter = Counter::new();
74+
///
75+
/// assert_eq!(5, counter.len());
76+
/// # });
77+
/// # }
78+
/// ```
79+
#[cfg_attr(feature = "docs", doc(cfg(unstable)))]
80+
#[cfg(any(feature = "unstable", feature = "docs"))]
81+
pub trait ExactSizeStream: Stream {
82+
/// Returns the exact number of times the stream will iterate.
83+
///
84+
/// This method has a default implementation, so you usually should not
85+
/// implement it directly. However, if you can provide a more efficient
86+
/// implementation, you can do so. See the [trait-level] docs for an
87+
/// example.
88+
///
89+
/// This function has the same safety guarantees as the [`size_hint`]
90+
/// function.
91+
///
92+
/// [trait-level]: trait.ExactSizeStream.html
93+
/// [`size_hint`]: trait.Stream.html#method.size_hint
94+
///
95+
/// # Examples
96+
///
97+
/// Basic usage:
98+
///
99+
/// ```
100+
/// // a finite range knows exactly how many times it will iterate
101+
/// let five = 0..5;
102+
///
103+
/// assert_eq!(5, five.len());
104+
/// ```
105+
fn len(&self) -> usize {
106+
let (lower, upper) = self.size_hint();
107+
// Note: This assertion is overly defensive, but it checks the invariant
108+
// guaranteed by the trait. If this trait were rust-internal,
109+
// we could use debug_assert!; assert_eq! will check all Rust user
110+
// implementations too.
111+
assert_eq!(upper, Some(lower));
112+
lower
113+
}
114+
}
115+
116+
impl<I: ExactSizeStream + ?Sized + Unpin> ExactSizeStream for &mut I {
117+
fn len(&self) -> usize {
118+
(**self).len()
119+
}
120+
}

src/stream/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ mod repeat;
3939
cfg_if! {
4040
if #[cfg(any(feature = "unstable", feature = "docs"))] {
4141
mod double_ended_stream;
42+
mod exact_size_stream;
4243
mod fused_stream;
4344
mod extend;
4445
mod from_stream;
4546
mod into_stream;
4647

4748
pub use double_ended_stream::DoubleEndedStream;
49+
pub use exact_size_stream::ExactSizeStream;
4850
pub use extend::Extend;
4951
pub use from_stream::FromStream;
5052
pub use into_stream::IntoStream;

0 commit comments

Comments
 (0)