Skip to content

Commit 5a9ba53

Browse files
feat(io): implement Read::bytes
1 parent 1552e8a commit 5a9ba53

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-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+
/// An iterator 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/mod.rs

+41
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod bytes;
12
mod read;
23
mod read_exact;
34
mod read_to_end;
@@ -303,6 +304,39 @@ cfg_if! {
303304
/// }) }
304305
/// ```
305306
fn by_ref(&mut self) -> &mut Self where Self: Sized { unreachable!() }
307+
308+
309+
/// Transforms this `Read` instance to a `Stream` over its bytes.
310+
///
311+
/// The returned type implements `Stream` where the `Item` is
312+
/// `Result<u8, io::Error>`.
313+
/// The yielded item is `Ok` if a byte was successfully read and `Err`
314+
/// otherwise. EOF is mapped to returning `None` from this iterator.
315+
///
316+
/// # Examples
317+
///
318+
/// [`File`][file]s implement `Read`:
319+
///
320+
/// [file]: ../fs/struct.File.html
321+
///
322+
/// ```no_run
323+
/// use async_std::io;
324+
/// use async_std::io::prelude::*;
325+
/// use async_std::fs::File;
326+
///
327+
/// fn main() -> io::Result<()> { async_std::task:.block_on(async {
328+
/// let mut f = File::open("foo.txt").await?;
329+
/// let mut s = f.bytes();
330+
///
331+
/// while let Some(v) = s.next().await {
332+
/// println!("{}", byte.unwrap());
333+
/// }
334+
/// Ok(())
335+
/// }) }
336+
/// ```
337+
fn bytes(self) -> Bytes<Self> where Self: Sized {
338+
unreachable!{}
339+
}
306340
}
307341

308342
impl<T: Read + Unpin + ?Sized> Read for Box<T> {
@@ -417,6 +451,13 @@ pub trait ReadExt: futures_io::AsyncRead {
417451
{
418452
self
419453
}
454+
455+
fn bytes(self) -> bytes::Bytes<Self>
456+
where
457+
Self: Sized,
458+
{
459+
bytes::Bytes { inner: self }
460+
}
420461
}
421462

422463
impl<T: futures_io::AsyncRead + ?Sized> ReadExt for T {}

0 commit comments

Comments
 (0)