Skip to content

Commit 383f7e9

Browse files
Merge #245
245: feat: missing Read and Write methods r=yoshuawuyts a=dignifiedquire Ref: #131 - [x] Read::by_ref - [x] Read::bytes - [x] Read::chain - [x] Read::take - [ ] Write::by_ref - [ ] ~~Write::write_fmt~~ postponed until #247 is solved Needs fixing: - [x] `BufRead` for `Take` - [x] `BufRead` for `Chain` - [ ] `by_ref` conflict between `Read` and `Write`, unable to add both, as they conflict, and the current state of things does not allow to differentiate between the two. Co-authored-by: dignifiedquire <[email protected]>
2 parents 8a5144f + 064b44f commit 383f7e9

File tree

4 files changed

+680
-0
lines changed

4 files changed

+680
-0
lines changed

src/io/read/bytes.rs

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use std::pin::Pin;
2+
3+
use crate::io::{self, Read};
4+
use crate::stream::stream::Stream;
5+
use crate::task::{Context, Poll};
6+
7+
/// A stream over `u8` values of a reader.
8+
///
9+
/// This struct is generally created by calling [`bytes`] on a reader.
10+
/// Please see the documentation of [`bytes`] for more details.
11+
///
12+
/// [`bytes`]: trait.Read.html#method.bytes
13+
#[derive(Debug)]
14+
pub struct Bytes<T> {
15+
pub(crate) inner: T,
16+
}
17+
18+
impl<T: Read + Unpin> Stream for Bytes<T> {
19+
type Item = io::Result<u8>;
20+
21+
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
22+
let mut byte = 0;
23+
24+
let rd = Pin::new(&mut self.inner);
25+
26+
match futures_core::ready!(rd.poll_read(cx, std::slice::from_mut(&mut byte))) {
27+
Ok(0) => Poll::Ready(None),
28+
Ok(..) => Poll::Ready(Some(Ok(byte))),
29+
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => Poll::Pending,
30+
Err(e) => Poll::Ready(Some(Err(e))),
31+
}
32+
}
33+
}
34+
35+
#[cfg(test)]
36+
mod tests {
37+
use crate::io;
38+
use crate::prelude::*;
39+
use crate::task;
40+
41+
#[test]
42+
fn test_bytes_basics() -> std::io::Result<()> {
43+
task::block_on(async move {
44+
let raw: Vec<u8> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
45+
let source: io::Cursor<Vec<u8>> = io::Cursor::new(raw.clone());
46+
47+
let mut s = source.bytes();
48+
49+
// TODO(@dignifiedquire): Use collect, once it is stable.
50+
let mut result = Vec::new();
51+
while let Some(byte) = s.next().await {
52+
result.push(byte?);
53+
}
54+
55+
assert_eq!(result, raw);
56+
57+
Ok(())
58+
})
59+
}
60+
}

src/io/read/chain.rs

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
use crate::io::IoSliceMut;
2+
use std::fmt;
3+
use std::pin::Pin;
4+
5+
use crate::io::{self, BufRead, Read};
6+
use crate::task::{Context, Poll};
7+
8+
/// Adaptor to chain together two readers.
9+
///
10+
/// This struct is generally created by calling [`chain`] on a reader.
11+
/// Please see the documentation of [`chain`] for more details.
12+
///
13+
/// [`chain`]: trait.Read.html#method.chain
14+
pub struct Chain<T, U> {
15+
pub(crate) first: T,
16+
pub(crate) second: U,
17+
pub(crate) done_first: bool,
18+
}
19+
20+
impl<T, U> Chain<T, U> {
21+
/// Consumes the `Chain`, returning the wrapped readers.
22+
///
23+
/// # Examples
24+
///
25+
/// ```no_run
26+
/// # fn main() -> async_std::io::Result<()> { async_std::task::block_on(async {
27+
/// #
28+
/// use async_std::prelude::*;
29+
/// use async_std::fs::File;
30+
///
31+
/// let foo_file = File::open("foo.txt").await?;
32+
/// let bar_file = File::open("bar.txt").await?;
33+
///
34+
/// let chain = foo_file.chain(bar_file);
35+
/// let (foo_file, bar_file) = chain.into_inner();
36+
/// #
37+
/// # Ok(()) }) }
38+
/// ```
39+
pub fn into_inner(self) -> (T, U) {
40+
(self.first, self.second)
41+
}
42+
43+
/// Gets references to the underlying readers in this `Chain`.
44+
///
45+
/// # Examples
46+
///
47+
/// ```no_run
48+
/// # fn main() -> async_std::io::Result<()> { async_std::task::block_on(async {
49+
/// #
50+
/// use async_std::prelude::*;
51+
/// use async_std::fs::File;
52+
///
53+
/// let foo_file = File::open("foo.txt").await?;
54+
/// let bar_file = File::open("bar.txt").await?;
55+
///
56+
/// let chain = foo_file.chain(bar_file);
57+
/// let (foo_file, bar_file) = chain.get_ref();
58+
/// #
59+
/// # Ok(()) }) }
60+
/// ```
61+
pub fn get_ref(&self) -> (&T, &U) {
62+
(&self.first, &self.second)
63+
}
64+
65+
/// Gets mutable references to the underlying readers in this `Chain`.
66+
///
67+
/// Care should be taken to avoid modifying the internal I/O state of the
68+
/// underlying readers as doing so may corrupt the internal state of this
69+
/// `Chain`.
70+
///
71+
/// # Examples
72+
///
73+
/// ```no_run
74+
/// # fn main() -> async_std::io::Result<()> { async_std::task::block_on(async {
75+
/// #
76+
/// use async_std::prelude::*;
77+
/// use async_std::fs::File;
78+
///
79+
/// let foo_file = File::open("foo.txt").await?;
80+
/// let bar_file = File::open("bar.txt").await?;
81+
///
82+
/// let mut chain = foo_file.chain(bar_file);
83+
/// let (foo_file, bar_file) = chain.get_mut();
84+
/// #
85+
/// # Ok(()) }) }
86+
/// ```
87+
pub fn get_mut(&mut self) -> (&mut T, &mut U) {
88+
(&mut self.first, &mut self.second)
89+
}
90+
}
91+
92+
impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
93+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94+
f.debug_struct("Chain")
95+
.field("t", &self.first)
96+
.field("u", &self.second)
97+
.finish()
98+
}
99+
}
100+
101+
impl<T: Read + Unpin, U: Read + Unpin> Read for Chain<T, U> {
102+
fn poll_read(
103+
mut self: Pin<&mut Self>,
104+
cx: &mut Context<'_>,
105+
buf: &mut [u8],
106+
) -> Poll<io::Result<usize>> {
107+
if !self.done_first {
108+
let rd = Pin::new(&mut self.first);
109+
110+
match futures_core::ready!(rd.poll_read(cx, buf)) {
111+
Ok(0) if !buf.is_empty() => self.done_first = true,
112+
Ok(n) => return Poll::Ready(Ok(n)),
113+
Err(err) => return Poll::Ready(Err(err)),
114+
}
115+
}
116+
117+
let rd = Pin::new(&mut self.second);
118+
rd.poll_read(cx, buf)
119+
}
120+
121+
fn poll_read_vectored(
122+
mut self: Pin<&mut Self>,
123+
cx: &mut Context<'_>,
124+
bufs: &mut [IoSliceMut<'_>],
125+
) -> Poll<io::Result<usize>> {
126+
if !self.done_first {
127+
let rd = Pin::new(&mut self.first);
128+
129+
match futures_core::ready!(rd.poll_read_vectored(cx, bufs)) {
130+
Ok(0) if !bufs.is_empty() => self.done_first = true,
131+
Ok(n) => return Poll::Ready(Ok(n)),
132+
Err(err) => return Poll::Ready(Err(err)),
133+
}
134+
}
135+
136+
let rd = Pin::new(&mut self.second);
137+
rd.poll_read_vectored(cx, bufs)
138+
}
139+
}
140+
141+
impl<T: BufRead + Unpin, U: BufRead + Unpin> BufRead for Chain<T, U> {
142+
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
143+
let Self {
144+
first,
145+
second,
146+
done_first,
147+
} = unsafe { self.get_unchecked_mut() };
148+
149+
if !*done_first {
150+
let first = unsafe { Pin::new_unchecked(first) };
151+
match futures_core::ready!(first.poll_fill_buf(cx)) {
152+
Ok(buf) if buf.is_empty() => {
153+
*done_first = true;
154+
}
155+
Ok(buf) => return Poll::Ready(Ok(buf)),
156+
Err(err) => return Poll::Ready(Err(err)),
157+
}
158+
}
159+
160+
let second = unsafe { Pin::new_unchecked(second) };
161+
second.poll_fill_buf(cx)
162+
}
163+
164+
fn consume(mut self: Pin<&mut Self>, amt: usize) {
165+
if !self.done_first {
166+
let rd = Pin::new(&mut self.first);
167+
rd.consume(amt)
168+
} else {
169+
let rd = Pin::new(&mut self.second);
170+
rd.consume(amt)
171+
}
172+
}
173+
}
174+
175+
#[cfg(test)]
176+
mod tests {
177+
use crate::io;
178+
use crate::prelude::*;
179+
use crate::task;
180+
181+
#[test]
182+
fn test_chain_basics() -> std::io::Result<()> {
183+
let source1: io::Cursor<Vec<u8>> = io::Cursor::new(vec![0, 1, 2]);
184+
let source2: io::Cursor<Vec<u8>> = io::Cursor::new(vec![3, 4, 5]);
185+
186+
task::block_on(async move {
187+
let mut buffer = Vec::new();
188+
189+
let mut source = source1.chain(source2);
190+
191+
assert_eq!(6, source.read_to_end(&mut buffer).await?);
192+
assert_eq!(buffer, vec![0, 1, 2, 3, 4, 5]);
193+
194+
Ok(())
195+
})
196+
}
197+
}

0 commit comments

Comments
 (0)