From 56944a61c1ed1d3366e7625349fde8556a2932e7 Mon Sep 17 00:00:00 2001 From: Al Liu Date: Thu, 21 Mar 2024 12:13:13 +0800 Subject: [PATCH] 0.2.2 --- .github/workflows/ci.yml | 25 ------- .github/workflows/loc.yml | 60 ++++++++++++++++ CHANGELOG.md | 5 ++ Cargo.toml | 7 +- README-zh_CN.md | 120 ++++++++++++++++++++++++++++++++ README.md | 76 ++++++++++++++++++++- src/future.rs | 115 ++++++++++++++++++++++++++++++- src/lib.rs | 100 ++++++++++++++++++++++++++- src/tokio.rs | 140 ++++++++++++++++++++++++++++++++------ src/tokio/peek.rs | 1 - src/tokio/peek_exact.rs | 1 - 11 files changed, 594 insertions(+), 56 deletions(-) create mode 100644 .github/workflows/loc.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 822923d..79cbea5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,31 +133,6 @@ jobs: - name: Run test run: cargo hack test --feature-powerset - docs: - name: docs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Cache cargo build and registry - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ubuntu-latest-docs-${{ hashFiles('**/Cargo.lock') }} - restore-keys: | - ubuntu-latest-docs- - - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ env.nightly }} - override: true - - name: "doc --lib --all-features" - run: cargo doc --lib --no-deps --all-features - env: - RUSTFLAGS: --cfg docsrs - RUSTDOCFLAGS: --cfg docsrs -Dwarnings - coverage: name: coverage runs-on: ubuntu-latest diff --git a/.github/workflows/loc.yml b/.github/workflows/loc.yml new file mode 100644 index 0000000..ce3c9fd --- /dev/null +++ b/.github/workflows/loc.yml @@ -0,0 +1,60 @@ +name: loc + +on: + push: + branches: + - main + paths-ignore: + - 'README.md' + - 'COPYRIGHT' + - 'LICENSE*' + - '**.md' + - '**.txt' + - 'art' + pull_request: + paths-ignore: + - 'README.md' + - 'COPYRIGHT' + - 'LICENSE*' + - '**.md' + - '**.txt' + - 'art' + workflow_dispatch: + +jobs: + loc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Rust + run: | + rustup update stable && rustup default stable + rustup component add clippy + rustup component add rustfmt + + - name: Install tokeit + run: | + cargo install tokeit --force + + - name: Count lines of code + run: | + tokeit + + - name: Upload loc to GitHub Gist + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GIST_PAT }} + script: | + const fs = require('fs'); + const output = fs.readFileSync('tokeit.json', 'utf8'); + const gistId = '327b2a8aef9003246e45c6e47fe63937'; + await github.rest.gists.update({ + gist_id: gistId, + files: { + "peekable": { + content: output + } + } + }); + console.log("Gist updated"); diff --git a/CHANGELOG.md b/CHANGELOG.md index 96e2eb4..ce20148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ ## RELEASED +### 0.2.2 (Mar 21st, 2024) + +- Add `consume` API +- Add DocTests for some APIs + ### 0.2.1 (Feb 10th, 2024) - Fix `peek_exact` bug and add `peek_exact_peek_exact_read_exact` test cases diff --git a/Cargo.toml b/Cargo.toml index 66bd4d9..03c8012 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,18 @@ [package] name = "peekable" -version = "0.2.1" +version = "0.2.2" edition = "2021" repository = "https://github.com/al8n/peekable" homepage = "https://github.com/al8n/peekable" documentation = "https://docs.rs/peekable" -description = "Peakable reader and async reader" +description = "Peekable reader and async reader, which enhance your network programming experience." license = "MIT OR Apache-2.0" rust-version = "1.56" keywords = ["peek", "io", "async", "tokio", "futures"] categories = ["asynchronous", "network-programming", "development-tools"] [features] -default = [] +default = ["smallvec"] future = ["futures-util", "pin-project-lite"] tokio = ["dep:tokio", "pin-project-lite", "bytes"] @@ -29,7 +29,6 @@ bytes = { version = "1", optional = true } [dev-dependencies] futures = { version = "0.3", features = ["executor"] } tokio = { version = "1", features = ["full"] } -tokio-util = { version = "0.7", features = ["compat"] } [package.metadata.docs.rs] all-features = true diff --git a/README-zh_CN.md b/README-zh_CN.md index e69de29..f9311af 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -0,0 +1,120 @@ +
+

Peekable

+
+
+ +Peekable reader and async reader, which enhance your network programming experience. + +[github][Github-url] +LoC +[Build][CI-url] +[codecov][codecov-url] + +[docs.rs][doc-url] +[crates.io][crates-url] +[crates.io][crates-url] +license + +English | [简体中文][zh-cn-url] + +
+ +## Installation + +```toml +[dependencies] +peekable = "0.2" +``` + +### Tokio I/O + +```toml +[dependencies] +peekable = { version = "0.2", features = ["tokio"] } +``` + +### Futures I/O + +```toml +[dependencies] +peekable = { version = "0.2", features = ["future"] } +``` + +## Examples + +### Std + +```rust +use std::{net::TcpStream, io::Read}; +use peekable::Peekable; + +let conn = TcpStream::connect("127.0.0.1:8080").unwrap(); +let mut peekable = Peekable::from(conn); + +let mut peeked = [0; 16]; +peekable.peek_exact(&mut peeked).unwrap(); + +let mut readed = [0; 16]; +peekable.read_exact(&mut readed).unwrap(); + +assert_eq!(peeked, readed); +``` + +### Tokio I/O + +```rust +use tokio::{net::TcpStream, io::AsyncReadExt}; +use peekable::tokio::AsyncPeekable; + +let conn = TcpStream::connect("127.0.0.1:8080").await.unwrap(); +let mut peekable = AsyncPeekable::from(conn); + +let mut peeked = [0; 16]; +peekable.peek_exact(&mut peeked).await.unwrap(); + +let mut readed = [0; 16]; +peekable.read_exact(&mut readed).await.unwrap(); + +assert_eq!(peeked, readed); +``` + +### Futures I/O + +```rust +use async_std::net::TcpStream; +use futures::AsyncReadExt; +use peekable::future::AsyncPeekable; + +let conn = TcpStream::connect("127.0.0.1:8080").await.unwrap(); +let mut peekable = AsyncPeekable::from(conn); + +let mut peeked = [0; 16]; +peekable.peek_exact(&mut peeked).await.unwrap(); + +let mut readed = [0; 16]; +peekable.read_exact(&mut readed).await.unwrap(); + +assert_eq!(peeked, readed); +``` + + +## TODO + +- [ ] Make peek buffer generic over `const N: usize` +- [ ] Add fill peek buffer API + +#### License + +`peekable` is under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details. + +Copyright (c) 2024 Al Liu. + +[Github-url]: https://github.com/al8n/peekable/ +[CI-url]: https://github.com/al8n/peekable/actions/workflows/ci.yml +[doc-url]: https://docs.rs/peekable +[crates-url]: https://crates.io/crates/peekable +[codecov-url]: https://app.codecov.io/gh/al8n/peekable/ +[zh-cn-url]: https://github.com/al8n/peekable/tree/main/README-zh_CN.md diff --git a/README.md b/README.md index 9c3daf0..f9311af 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,16 @@
-Peakable reader and async reader +Peekable reader and async reader, which enhance your network programming experience. [github][Github-url] +LoC [Build][CI-url] [codecov][codecov-url] [docs.rs][doc-url] [crates.io][crates-url] [crates.io][crates-url] - license English | [简体中文][zh-cn-url] @@ -26,6 +26,78 @@ English | [简体中文][zh-cn-url] peekable = "0.2" ``` +### Tokio I/O + +```toml +[dependencies] +peekable = { version = "0.2", features = ["tokio"] } +``` + +### Futures I/O + +```toml +[dependencies] +peekable = { version = "0.2", features = ["future"] } +``` + +## Examples + +### Std + +```rust +use std::{net::TcpStream, io::Read}; +use peekable::Peekable; + +let conn = TcpStream::connect("127.0.0.1:8080").unwrap(); +let mut peekable = Peekable::from(conn); + +let mut peeked = [0; 16]; +peekable.peek_exact(&mut peeked).unwrap(); + +let mut readed = [0; 16]; +peekable.read_exact(&mut readed).unwrap(); + +assert_eq!(peeked, readed); +``` + +### Tokio I/O + +```rust +use tokio::{net::TcpStream, io::AsyncReadExt}; +use peekable::tokio::AsyncPeekable; + +let conn = TcpStream::connect("127.0.0.1:8080").await.unwrap(); +let mut peekable = AsyncPeekable::from(conn); + +let mut peeked = [0; 16]; +peekable.peek_exact(&mut peeked).await.unwrap(); + +let mut readed = [0; 16]; +peekable.read_exact(&mut readed).await.unwrap(); + +assert_eq!(peeked, readed); +``` + +### Futures I/O + +```rust +use async_std::net::TcpStream; +use futures::AsyncReadExt; +use peekable::future::AsyncPeekable; + +let conn = TcpStream::connect("127.0.0.1:8080").await.unwrap(); +let mut peekable = AsyncPeekable::from(conn); + +let mut peeked = [0; 16]; +peekable.peek_exact(&mut peeked).await.unwrap(); + +let mut readed = [0; 16]; +peekable.read_exact(&mut readed).await.unwrap(); + +assert_eq!(peeked, readed); +``` + + ## TODO - [ ] Make peek buffer generic over `const N: usize` diff --git a/src/future.rs b/src/future.rs index b822185..2d75587 100644 --- a/src/future.rs +++ b/src/future.rs @@ -1,13 +1,11 @@ use std::{ - cmp, future::Future, - io::Result, ops::DerefMut, pin::Pin, task::{Context, Poll}, }; -use futures_util::{io::IoSliceMut, AsyncRead}; +use futures_util::AsyncRead; use super::*; @@ -245,6 +243,19 @@ impl AsyncPeek for AsyncPeekable { impl AsyncPeekable { /// Creates a new `AsyncPeekable` which will wrap the given reader. + /// + /// The peek buffer will have the default capacity. + /// + /// # Examples + /// + /// ```rust + /// use peekable::future::AsyncPeekable; + /// + /// # futures::executor::block_on(async { + /// let reader = futures::io::Cursor::new(&b"hello"[..]); + /// let peekable = AsyncPeekable::new(reader); + /// # }); + /// #[inline] pub fn new(reader: R) -> Self { Self { @@ -255,6 +266,16 @@ impl AsyncPeekable { /// Creates a new peekable wrapper around the given reader with the specified /// capacity for the peek buffer. + /// + /// # Examples + /// + /// ```rust + /// use peekable::future::AsyncPeekable; + /// + /// # futures::executor::block_on(async { + /// let reader = futures::io::Cursor::new([0; 1024]); + /// let peekable = AsyncPeekable::with_capacity(reader, 1024); + /// # }); #[inline] pub fn with_capacity(reader: R, capacity: usize) -> Self { Self { @@ -263,9 +284,57 @@ impl AsyncPeekable { } } + /// Consumes the peek buffer and returns the buffer. + /// + /// # Examples + /// + /// ```rust + /// use peekable::future::AsyncPeekable; + /// + /// # futures::executor::block_on(async { + /// let reader = futures::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let buffer = peekable.consume(); + /// assert_eq!(buffer.as_slice(), [1, 2].as_slice()); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [3, 4]); + /// # }); + /// ``` + pub fn consume(&mut self) -> Buffer { + mem::take(&mut self.buffer) + } + /// Returns the bytes already be peeked into memory and a mutable reference to the underlying reader. /// /// **WARNING: If you invoke `AsyncRead` or `AsyncReadExt` methods on the underlying reader, may lead to unexpected read behaviors.** + /// + /// # Examples + /// + /// ```rust + /// use peekable::future::AsyncPeekable; + /// + /// # futures::executor::block_on(async { + /// let reader = futures::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (buffer, reader) = peekable.get_mut(); + /// assert_eq!(buffer, [1, 2].as_slice()); + /// # }); + /// ```` #[inline] pub fn get_mut(&mut self) -> (&[u8], &mut R) { (&self.buffer, &mut self.reader) @@ -274,12 +343,48 @@ impl AsyncPeekable { /// Returns the bytes already be peeked into memory and a reference to the underlying reader. /// /// **WARNING: If you invoke `AsyncRead` or `AsyncReadExt` methods on the underlying reader, may lead to unexpected read behaviors.** + /// + /// # Examples + /// + /// ```rust + /// use peekable::future::AsyncPeekable; + /// + /// # futures::executor::block_on(async { + /// let reader = futures::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (buffer, reader) = peekable.get_ref(); + /// assert_eq!(buffer, [1, 2].as_slice()); + /// # }); #[inline] pub fn get_ref(&self) -> (&[u8], &R) { (&self.buffer, &self.reader) } /// Consumes the `AsyncPeekable`, returning the a vec may contain the bytes already be peeked into memory and the wrapped reader. + /// + /// # Examples + /// + /// ```rust + /// use peekable::future::AsyncPeekable; + /// + /// # futures::executor::block_on(async { + /// let reader = futures::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (buffer, reader) = peekable.into_components(); + /// assert_eq!(buffer.as_slice(), [1, 2].as_slice()); + /// # }); #[inline] pub fn into_components(self) -> (Buffer, R) { (self.buffer, self.reader) @@ -479,6 +584,10 @@ impl AsyncPeekable { /// assert_eq!(bytes, 4); /// assert_eq!(buffer, String::from("1234")); /// + /// // peek invalid utf-8 + /// let mut peekable = Cursor::new([255; 4]).peekable(); + /// let mut buffer = String::with_capacity(4); + /// assert!(peekable.peek_to_string(&mut buffer).await.is_err()); /// # Ok::<(), Box>(()) }).unwrap(); /// ``` pub fn peek_to_string<'a>(&'a mut self, buf: &'a mut String) -> PeekToString<'a, R> diff --git a/src/lib.rs b/src/lib.rs index daa017a..ba8a505 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,6 +111,14 @@ impl From for Peekable { impl Peekable { /// Creates a new peekable wrapper around the given reader. + /// + /// # Examples + /// + /// ```rust + /// use std::io::Cursor; + /// + /// let peekable = peekable::Peekable::new(Cursor::new([1, 2, 3, 4])); + /// ``` pub fn new(reader: R) -> Self { Self { reader, @@ -120,6 +128,14 @@ impl Peekable { /// Creates a new peekable wrapper around the given reader with the specified /// capacity for the peek buffer. + /// + /// # Examples + /// + /// ```rust + /// use std::io::Cursor; + /// + /// let peekable = peekable::Peekable::with_capacity(Cursor::new([0; 1024]), 1024); + /// ``` pub fn with_capacity(reader: R, capacity: usize) -> Self { Self { reader, @@ -127,9 +143,51 @@ impl Peekable { } } + /// Clears the peek buffer. + /// + /// # Examples + /// + /// ```rust + /// use std::io::Cursor; + /// + /// let mut peekable = peekable::Peekable::from(Cursor::new([1, 2, 3, 4])); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let consumed = peekable.consume(); + /// assert_eq!(consumed.as_slice(), [1, 2].as_slice()); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [3, 4]); + /// ``` + pub fn consume(&mut self) -> Buffer { + mem::take(&mut self.buffer) + } + /// Returns the bytes already be peeked into memory and a mutable reference to the underlying reader. /// /// **WARNING: If you invoke `AsyncRead` or `AsyncReadExt` methods on the underlying reader, may lead to unexpected read behaviors.** + /// + /// # Examples + /// + /// ```rust + /// use std::io::Cursor; + /// + /// let mut peekable = peekable::Peekable::new(Cursor::new([1, 2, 3, 4])); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (peeked, reader) = peekable.get_mut(); + /// assert_eq!(peeked, [1, 2]); + /// ``` #[inline] pub fn get_mut(&mut self) -> (&[u8], &mut R) { (&self.buffer, &mut self.reader) @@ -138,12 +196,47 @@ impl Peekable { /// Returns the bytes already be peeked into memory and a reference to the underlying reader. /// /// **WARNING: If you invoke `AsyncRead` or `AsyncReadExt` methods on the underlying reader, may lead to unexpected read behaviors.** + /// + /// # Examples + /// + /// ```rust + /// use std::io::Cursor; + /// + /// let mut peekable = peekable::Peekable::new(Cursor::new([1, 2, 3, 4])); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (peeked, reader) = peekable.get_ref(); + /// assert_eq!(peeked, [1, 2]); + /// ``` #[inline] pub fn get_ref(&self) -> (&[u8], &R) { (&self.buffer, &self.reader) } /// Consumes the `AsyncPeekable`, returning the a vec may contain the bytes already be peeked into memory and the wrapped reader. + /// + /// + /// # Examples + /// + /// ```rust + /// use std::io::Cursor; + /// + /// let mut peekable = peekable::Peekable::new(Cursor::new([1, 2, 3, 4])); + /// + /// let mut output = [0u8; 2]; + /// + /// let bytes = peekable.peek(&mut output).unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (peeked, reader) = peekable.into_components(); + /// + /// assert_eq!(peeked.as_slice(), [1, 2].as_slice()); + /// ``` #[inline] pub fn into_components(self) -> (Buffer, R) { (self.buffer, self.reader) @@ -415,6 +508,11 @@ impl Peekable { /// /// assert_eq!(bytes, 4); /// assert_eq!(buffer, String::from("1234")); + /// + /// // peek invalid utf-8 + /// let mut peekable = Cursor::new([255; 4]).peekable(); + /// let mut buffer = String::with_capacity(4); + /// assert!(peekable.peek_to_string(&mut buffer).is_err()); /// # Ok(()) /// # } /// ``` @@ -583,7 +681,7 @@ impl PeekExt for R {} #[cfg(test)] mod tests { use super::*; - use std::io::{Cursor, Read}; + use std::io::Cursor; #[test] fn test_peek_exact_peek_exact_read_exact() { diff --git a/src/tokio.rs b/src/tokio.rs index b833ca2..dda9f51 100644 --- a/src/tokio.rs +++ b/src/tokio.rs @@ -232,6 +232,18 @@ impl AsyncPeek for AsyncPeekable { impl AsyncPeekable { /// Creates a new `AsyncPeekable` which will wrap the given peeker. + /// + /// The peek buffer will have a capacity of 1024 bytes. + /// + /// # Examples + /// + /// ```rust + /// use peekable::tokio::AsyncPeekable; + /// + /// # tokio::runtime::Runtime::new().unwrap().block_on(async { + /// let reader = std::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// # }); #[inline] pub fn new(reader: R) -> Self { Self { @@ -242,6 +254,16 @@ impl AsyncPeekable { /// Creates a new `AsyncPeekable` which will wrap the given peeker with the specified /// capacity for the peek buffer. + /// + /// # Examples + /// + /// ```rust + /// use peekable::tokio::AsyncPeekable; + /// + /// # tokio::runtime::Runtime::new().unwrap().block_on(async { + /// let reader = std::io::Cursor::new([0; 1024]); + /// let mut peekable = AsyncPeekable::with_capacity(reader, 1024); + /// # }); #[inline] pub fn with_capacity(reader: R, capacity: usize) -> Self { Self { @@ -250,9 +272,56 @@ impl AsyncPeekable { } } + /// Consumes the peek buffer and returns the buffer. + /// + /// # Examples + /// + /// ```rust + /// use peekable::tokio::AsyncPeekable; + /// + /// # tokio::runtime::Runtime::new().unwrap().block_on(async { + /// let reader = std::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let buffer = peekable.consume(); + /// assert_eq!(buffer.as_slice(), [1, 2].as_slice()); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [3, 4]); + /// # }); + /// ``` + pub fn consume(&mut self) -> Buffer { + core::mem::take(&mut self.buffer) + } + /// Returns the bytes already be peeked into memory and a mutable reference to the underlying reader. /// /// **WARNING: If you invoke `AsyncRead` or `AsyncReadExt` methods on the underlying reader, may lead to unexpected read behaviors.** + /// + /// # Examples + /// + /// ```rust + /// use peekable::tokio::AsyncPeekable; + /// + /// # tokio::runtime::Runtime::new().unwrap().block_on(async { + /// let reader = std::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (buffer, reader) = peekable.get_mut(); + /// assert_eq!(buffer, [1, 2]); + /// # }); #[inline] pub fn get_mut(&mut self) -> (&[u8], &mut R) { (&self.buffer, &mut self.reader) @@ -261,12 +330,48 @@ impl AsyncPeekable { /// Returns the bytes already be peeked into memory and a reference to the underlying reader. /// /// **WARNING: If you invoke `AsyncRead` or `AsyncReadExt` methods on the underlying reader, may lead to unexpected read behaviors.** + /// + /// # Examples + /// + /// ```rust + /// use peekable::tokio::AsyncPeekable; + /// + /// # tokio::runtime::Runtime::new().unwrap().block_on(async { + /// let reader = std::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (buffer, reader) = peekable.get_ref(); + /// assert_eq!(buffer, [1, 2]); + /// # }); #[inline] pub fn get_ref(&self) -> (&[u8], &R) { (&self.buffer, &self.reader) } /// Consumes the `AsyncPeekable`, returning the a vec may contain the bytes already be peeked into memory and the wrapped reader. + /// + /// # Examples + /// + /// ```rust + /// use peekable::tokio::AsyncPeekable; + /// + /// # tokio::runtime::Runtime::new().unwrap().block_on(async { + /// let reader = std::io::Cursor::new([1, 2, 3, 4]); + /// let mut peekable = AsyncPeekable::from(reader); + /// + /// let mut output = [0u8; 2]; + /// let bytes = peekable.peek(&mut output).await.unwrap(); + /// assert_eq!(bytes, 2); + /// assert_eq!(output, [1, 2]); + /// + /// let (buffer, reader) = peekable.into_components(); + /// assert_eq!(buffer.as_slice(), [1, 2]); + /// # }); #[inline] pub fn into_components(self) -> (Buffer, R) { (self.buffer, self.reader) @@ -303,13 +408,11 @@ impl AsyncPeekable { /// ``` /// # #[tokio::main] /// # async fn main() -> std::io::Result<()> { - /// use futures::io::Cursor; - /// use tokio::io::AsyncReadExt; - /// use tokio_util::compat::FuturesAsyncReadCompatExt; /// use peekable::tokio::AsyncPeekExt; + /// use tokio::io::AsyncReadExt; /// /// - /// let mut peekable = Cursor::new([1, 2, 3, 4]).compat().peekable(); + /// let mut peekable = std::io::Cursor::new([1, 2, 3, 4]).peekable(); /// let mut output = [0u8; 5]; /// /// let bytes = peekable.peek(&mut output[..3]).await?; @@ -372,12 +475,11 @@ impl AsyncPeekable { /// ``` /// # #[tokio::main] /// # async fn main() -> std::io::Result<()> { - /// use futures::io::Cursor; + /// use std::io::Cursor; /// use tokio::io::AsyncReadExt; - /// use tokio_util::compat::FuturesAsyncReadCompatExt; /// use peekable::tokio::AsyncPeekExt; /// - /// let mut peekable = Cursor::new([1, 2, 3, 4]).compat().peekable(); + /// let mut peekable = Cursor::new([1, 2, 3, 4]).peekable(); /// let mut output = [0u8; 4]; /// /// peekable.peek_exact(&mut output).await?; @@ -407,12 +509,11 @@ impl AsyncPeekable { /// # #[tokio::main] /// # async fn main() -> std::io::Result<()> { /// - /// use futures::io::Cursor; + /// use std::io::Cursor; /// use tokio::io::AsyncReadExt; - /// use tokio_util::compat::FuturesAsyncReadCompatExt; /// use peekable::tokio::AsyncPeekExt; /// - /// let mut peekable = Cursor::new([1, 2, 3, 4]).compat().peekable(); + /// let mut peekable = Cursor::new([1, 2, 3, 4]).peekable(); /// let mut output = [0u8; 5]; /// /// let result = peekable.peek_exact(&mut output).await; @@ -462,12 +563,11 @@ impl AsyncPeekable { /// ``` /// # #[tokio::main] /// # async fn main() -> std::io::Result<()> { - /// use futures::io::Cursor; + /// use std::io::Cursor; /// use tokio::io::AsyncReadExt; - /// use tokio_util::compat::FuturesAsyncReadCompatExt; /// use peekable::tokio::AsyncPeekExt; /// - /// let mut peekable = Cursor::new([1, 2, 3, 4]).compat().peekable(); + /// let mut peekable = Cursor::new([1, 2, 3, 4]).peekable(); /// let mut output = Vec::with_capacity(4); /// /// let bytes = peekable.peek_to_end(&mut output).await?; @@ -501,12 +601,11 @@ impl AsyncPeekable { /// ``` /// # #[tokio::main] /// # async fn main() -> std::io::Result<()> { - /// use futures::io::Cursor; + /// use std::io::Cursor; /// use tokio::io::AsyncReadExt; - /// use tokio_util::compat::FuturesAsyncReadCompatExt; /// use peekable::tokio::AsyncPeekExt; /// - /// let mut peekable = Cursor::new(&b"1234"[..]).compat().peekable(); + /// let mut peekable = Cursor::new(&b"1234"[..]).peekable(); /// let mut buffer = String::with_capacity(4); /// /// let bytes = peekable.peek_to_string(&mut buffer).await?; @@ -521,6 +620,10 @@ impl AsyncPeekable { /// assert_eq!(bytes, 4); /// assert_eq!(buffer, String::from("1234")); /// + /// // peek invalid utf-8 + /// let mut peekable = Cursor::new([255; 4]).peekable(); + /// let mut buffer = String::with_capacity(4); + /// assert!(peekable.peek_to_string(&mut buffer).await.is_err()); /// # Ok::<(), std::io::Error>(()) /// # } /// ``` @@ -535,13 +638,12 @@ impl AsyncPeekable { #[cfg(test)] mod tests { use super::*; - use futures::io::Cursor; + use std::io::Cursor; use tokio::io::AsyncReadExt; - use tokio_util::compat::FuturesAsyncReadCompatExt; #[tokio::test] async fn test_peek_exact_peek_exact_read_exact() { - let mut peekable = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8, 9]).compat().peekable(); + let mut peekable = Cursor::new([1, 2, 3, 4, 5, 6, 7, 8, 9]).peekable(); let mut buf1 = [0; 2]; peekable.peek_exact(&mut buf1).await.unwrap(); assert_eq!(buf1, [1, 2]); diff --git a/src/tokio/peek.rs b/src/tokio/peek.rs index bbc0db0..2d8ee4d 100644 --- a/src/tokio/peek.rs +++ b/src/tokio/peek.rs @@ -4,7 +4,6 @@ use pin_project_lite::pin_project; use std::future::Future; use std::io; use std::marker::PhantomPinned; -use std::marker::Unpin; use std::pin::Pin; use std::task::{Context, Poll}; diff --git a/src/tokio/peek_exact.rs b/src/tokio/peek_exact.rs index ce538bc..635b127 100644 --- a/src/tokio/peek_exact.rs +++ b/src/tokio/peek_exact.rs @@ -3,7 +3,6 @@ use pin_project_lite::pin_project; use std::future::Future; use std::io; use std::marker::PhantomPinned; -use std::marker::Unpin; use std::pin::Pin; use std::task::{Context, Poll};