Skip to content

Commit e1deaa5

Browse files
yoshuawuytsStjepan Glavina
and
Stjepan Glavina
committed
Add BufRead::split (#312)
* add BufRead::split Signed-off-by: Yoshua Wuyts <[email protected]> * fix docs Signed-off-by: Yoshua Wuyts <[email protected]> * Update src/io/buf_read/mod.rs Co-Authored-By: Stjepan Glavina <[email protected]>
1 parent 5f52efe commit e1deaa5

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

Diff for: src/io/buf_read/mod.rs

+54
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
mod lines;
22
mod read_line;
33
mod read_until;
4+
mod split;
45

56
pub use lines::Lines;
7+
pub use split::Split;
8+
69
use read_line::ReadLineFuture;
710
use read_until::ReadUntilFuture;
811

@@ -226,6 +229,57 @@ extension_trait! {
226229
read: 0,
227230
}
228231
}
232+
233+
#[doc = r#"
234+
Returns a stream over the contents of this reader split on the byte `byte`.
235+
236+
The stream returned from this function will return instances of
237+
[`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
238+
the delimiter byte at the end.
239+
240+
This function will yield errors whenever [`read_until`] would have
241+
also yielded an error.
242+
243+
[`io::Result`]: type.Result.html
244+
[`Vec<u8>`]: ../vec/struct.Vec.html
245+
[`read_until`]: #method.read_until
246+
247+
# Examples
248+
249+
[`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
250+
this example, we use [`Cursor`] to iterate over all hyphen delimited
251+
segments in a byte slice
252+
253+
[`Cursor`]: struct.Cursor.html
254+
255+
```
256+
# fn main() -> std::io::Result<()> { async_std::task::block_on(async {
257+
#
258+
use async_std::prelude::*;
259+
use async_std::io;
260+
261+
let cursor = io::Cursor::new(b"lorem-ipsum-dolor");
262+
263+
let mut split_iter = cursor.split(b'-').map(|l| l.unwrap());
264+
assert_eq!(split_iter.next().await, Some(b"lorem".to_vec()));
265+
assert_eq!(split_iter.next().await, Some(b"ipsum".to_vec()));
266+
assert_eq!(split_iter.next().await, Some(b"dolor".to_vec()));
267+
assert_eq!(split_iter.next().await, None);
268+
#
269+
# Ok(()) }) }
270+
```
271+
"#]
272+
fn split(self, byte: u8) -> Split<Self>
273+
where
274+
Self: Sized,
275+
{
276+
Split {
277+
reader: self,
278+
buf: Vec::new(),
279+
delim: byte,
280+
read: 0,
281+
}
282+
}
229283
}
230284

231285
impl<T: BufRead + Unpin + ?Sized> BufRead for Box<T> {

Diff for: src/io/buf_read/split.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use std::mem;
2+
use std::pin::Pin;
3+
4+
use super::read_until_internal;
5+
use crate::io::{self, BufRead};
6+
use crate::stream::Stream;
7+
use crate::task::{Context, Poll};
8+
9+
/// A stream over the contents of an instance of [`BufRead`] split on a particular byte.
10+
///
11+
/// This stream is created by the [`split`] method on types that implement [`BufRead`].
12+
///
13+
/// This type is an async version of [`std::io::Split`].
14+
///
15+
/// [`split`]: trait.BufRead.html#method.lines
16+
/// [`BufRead`]: trait.BufRead.html
17+
/// [`std::io::Split`]: https://doc.rust-lang.org/std/io/struct.Split.html
18+
#[derive(Debug)]
19+
pub struct Split<R> {
20+
pub(crate) reader: R,
21+
pub(crate) buf: Vec<u8>,
22+
pub(crate) read: usize,
23+
pub(crate) delim: u8,
24+
}
25+
26+
impl<R: BufRead> Stream for Split<R> {
27+
type Item = io::Result<Vec<u8>>;
28+
29+
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
30+
let Self {
31+
reader,
32+
buf,
33+
read,
34+
delim,
35+
} = unsafe { self.get_unchecked_mut() };
36+
let reader = unsafe { Pin::new_unchecked(reader) };
37+
let n = futures_core::ready!(read_until_internal(reader, cx, *delim, buf, read))?;
38+
if n == 0 && buf.is_empty() {
39+
return Poll::Ready(None);
40+
}
41+
if buf[buf.len() - 1] == *delim {
42+
buf.pop();
43+
}
44+
Poll::Ready(Some(Ok(mem::replace(buf, vec![]))))
45+
}
46+
}

0 commit comments

Comments
 (0)