asynchronous-codec-0.7.0/.cargo_vcs_info.json0000644000000001360000000000100146460ustar { "git": { "sha1": "c818a83906891caf8aadcae8f899727c2c8393a8" }, "path_in_vcs": "" }asynchronous-codec-0.7.0/.github/dependabot.yml000064400000000000000000000001541046102023000176260ustar 00000000000000version: 2 updates: - package-ecosystem: "cargo" directory: "/" schedule: interval: "daily" asynchronous-codec-0.7.0/.github/workflows/rust.yml000064400000000000000000000051051046102023000205540ustar 00000000000000on: [push, pull_request] name: Continuous integration jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true # Caching - name: Cache cargo registry uses: actions/cache@v1 with: path: ~/.cargo/registry key: cargo-registry-${{ hashFiles('Cargo.toml') }} - name: Cache cargo index uses: actions/cache@v1 with: path: ~/.cargo/git key: cargo-index-${{ hashFiles('Cargo.toml') }} - uses: actions-rs/cargo@v1 with: command: check args: --all --all-features test: name: Test Suite runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true # Caching - name: Cache cargo registry uses: actions/cache@v1 with: path: ~/.cargo/registry key: cargo-registry-${{ hashFiles('Cargo.toml') }} - name: Cache cargo index uses: actions/cache@v1 with: path: ~/.cargo/git key: cargo-index-${{ hashFiles('Cargo.toml') }} - uses: actions-rs/cargo@v1 with: command: test args: --all --all-features fmt: name: Rustfmt runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - run: rustup component add rustfmt - uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check clippy: name: Clippy runs-on: ubuntu-latest continue-on-error: true steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - run: rustup component add clippy # Caching - name: Cache cargo registry uses: actions/cache@v1 with: path: ~/.cargo/registry key: cargo-registry-${{ hashFiles('Cargo.toml') }} - name: Cache cargo index uses: actions/cache@v1 with: path: ~/.cargo/git key: cargo-index-${{ hashFiles('Cargo.toml') }} - uses: actions-rs/cargo@v1 continue-on-error: true with: command: clippy args: -- -D warnings asynchronous-codec-0.7.0/.gitignore000064400000000000000000000000361046102023000154250ustar 00000000000000/target **/*.rs.bk Cargo.lock asynchronous-codec-0.7.0/.travis.yml000064400000000000000000000000651046102023000155500ustar 00000000000000language: rust rust: - stable - beta - nightly asynchronous-codec-0.7.0/CHANGELOG.md000064400000000000000000000020461046102023000152510ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.7.0] ### Changed - Use GATs for `Encoder` trait to allow encoding of borrowed data. See [PR 9](https://github.com/mxinden/asynchronous-codec/pull/9). ## [0.6.2] ### Fixed - Error handling in `CborCodec` and `JsonCodec` `decode`, more specifically not advancing the data buffer on partial decoding. See [#7](https://github.com/mxinden/asynchronous-codec/pull/7) for details. ## [0.6.1] - 2022-11-08 ### Added - `Framed::send_high_water_mark` and `Framed::set_send_high_water_mark` [#3]. [#3]: https://github.com/mxinden/asynchronous-codec/pull/3 ## [0.6.0] - 2021-02-01 ### Changed - Permit conversion into and creation from "parts" [#2](https://github.com/mxinden/asynchronous-codec/pull/2). ## [0.5.0] - 2021-01-06 ### Changed - Update to `bytes` `v1` and `pin-project-lite` `v0.2`. asynchronous-codec-0.7.0/Cargo.toml0000644000000031430000000000100126450ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "asynchronous-codec" version = "0.7.0" authors = ["Max Inden "] description = "Utilities for encoding and decoding frames using `async/await`" homepage = "https://github.com/mxinden/asynchronous-codec" documentation = "https://docs.rs/crate/asynchronous-codec" readme = "README.md" keywords = [ "future", "futures", "async", "codec", ] categories = [ "asynchronous", "network-programming", ] license = "MIT" repository = "https://github.com/mxinden/asynchronous-codec" [package.metadata.docs.rs] all-features = true [dependencies.bytes] version = "1" [dependencies.futures-sink] version = "0.3" [dependencies.futures-util] version = "0.3" features = ["io"] [dependencies.memchr] version = "2" [dependencies.pin-project-lite] version = "0.2" [dependencies.serde] version = "1" features = ["derive"] optional = true [dependencies.serde_cbor] version = "0.11" optional = true [dependencies.serde_json] version = "1" optional = true [dev-dependencies.futures] version = "0.3" [features] cbor = [ "serde", "serde_cbor", ] default = [] json = [ "serde", "serde_json", ] asynchronous-codec-0.7.0/Cargo.toml.orig000064400000000000000000000020011046102023000163160ustar 00000000000000[package] name = "asynchronous-codec" edition = "2018" version = "0.7.0" authors = ["Max Inden "] description = "Utilities for encoding and decoding frames using `async/await`" license = "MIT" readme = "README.md" repository = "https://github.com/mxinden/asynchronous-codec" homepage = "https://github.com/mxinden/asynchronous-codec" documentation = "https://docs.rs/crate/asynchronous-codec" keywords = ["future", "futures", "async", "codec"] categories = ["asynchronous", "network-programming"] [features] default = [] json = [ "serde", "serde_json" ] cbor = [ "serde", "serde_cbor" ] [dependencies] bytes = "1" futures-sink = "0.3" futures-util = { version = "0.3", features = ["io"] } memchr = "2" pin-project-lite = "0.2" [dev-dependencies] futures = "0.3" [dependencies.serde] version = "1" optional = true features = [ "derive" ] [dependencies.serde_json] version = "1" optional = true [dependencies.serde_cbor] version = "0.11" optional = true [package.metadata.docs.rs] all-features = true asynchronous-codec-0.7.0/LICENSE000064400000000000000000000021231046102023000144410ustar 00000000000000MIT License Copyright (c) 2019 - 2020 Matt Hunzinger Copyright (c) 2021 Max Inden Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. asynchronous-codec-0.7.0/README.md000064400000000000000000000020231046102023000147120ustar 00000000000000# Asynchronous Codec Utilities for encoding and decoding frames using async/await. This is a fork of [`futures-codec`](https://github.com/matthunz/futures-codec) by [Matt Hunzinger](https://github.com/matthunz) borrowing many concepts from [`tokio-codec`](https://crates.io/crates/tokio-codec). Contains adapters to go from streams of bytes, `AsyncRead` and `AsyncWrite`, to framed streams implementing `Sink` and `Stream`. Framed streams are also known as transports. [![Latest Version](https://img.shields.io/crates/v/asynchronous-codec.svg)](https://crates.io/crates/asynchronous-codec) [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/asynchronous-codec) ![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg) ### Example ```rust use asynchronous_codec::{LinesCodec, Framed}; async fn main() { // let stream = ... let mut framed = Framed::new(stream, LinesCodec {}); while let Some(line) = framed.try_next().await.unwrap() { println!("{:?}", line); } } ``` asynchronous-codec-0.7.0/benches/lines.rs000064400000000000000000000032031046102023000165230ustar 00000000000000#![feature(test)] extern crate test; use asynchronous_codec::{FramedRead, LinesCodec}; use futures::{executor, io::Cursor, TryStreamExt}; #[bench] fn short(b: &mut test::Bencher) { let data = [ ["a"; 16].join("b"), ["b"; 16].join("c"), ["c"; 16].join("d"), ] .join("\n"); b.iter(|| { executor::block_on(async { let read = Cursor::new(test::black_box(&data)); let mut framed = FramedRead::new(read, LinesCodec {}); framed.try_next().await.unwrap(); framed.try_next().await.unwrap(); framed.try_next().await.is_ok() }) }) } #[bench] fn medium(b: &mut test::Bencher) { let data = [ ["a"; 128].join("b"), ["b"; 128].join("c"), ["c"; 128].join("d"), ] .join("\n"); b.iter(|| { executor::block_on(async { let read = Cursor::new(test::black_box(&data)); let mut framed = FramedRead::new(read, LinesCodec {}); framed.try_next().await.unwrap(); framed.try_next().await.unwrap(); framed.try_next().await.is_ok() }) }) } #[bench] fn long(b: &mut test::Bencher) { let data = [ ["a"; 2048].join("b"), ["b"; 2048].join("c"), ["c"; 2048].join("d"), ] .join("\n"); b.iter(|| { executor::block_on(async { let read = Cursor::new(test::black_box(&data)); let mut framed = FramedRead::new(read, LinesCodec {}); framed.try_next().await.unwrap(); framed.try_next().await.unwrap(); framed.try_next().await.is_ok() }) }) } asynchronous-codec-0.7.0/src/codec/bytes.rs000064400000000000000000000024271046102023000170030ustar 00000000000000use crate::{Decoder, Encoder}; use bytes::{Bytes, BytesMut}; use std::io::Error; /// A simple codec that ships bytes around /// /// # Example /// /// ``` /// # futures::executor::block_on(async move { /// use bytes::Bytes; /// use futures::{SinkExt, TryStreamExt}; /// use futures::io::Cursor; /// use asynchronous_codec::{BytesCodec, Framed}; /// /// let mut buf = vec![]; /// // Cursor implements AsyncRead and AsyncWrite /// let cur = Cursor::new(&mut buf); /// let mut framed = Framed::new(cur, BytesCodec); /// /// framed.send(Bytes::from("Hello World!")).await?; /// /// while let Some(bytes) = framed.try_next().await? { /// dbg!(bytes); /// } /// # Ok::<_, std::io::Error>(()) /// # }).unwrap(); /// ``` pub struct BytesCodec; impl Encoder for BytesCodec { type Item<'a> = Bytes; type Error = Error; fn encode(&mut self, src: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { dst.extend_from_slice(&src); Ok(()) } } impl Decoder for BytesCodec { type Item = Bytes; type Error = Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { let len = src.len(); if len > 0 { Ok(Some(src.split_to(len).freeze())) } else { Ok(None) } } } asynchronous-codec-0.7.0/src/codec/cbor.rs000064400000000000000000000161051046102023000166000ustar 00000000000000use std::io::Error as IoError; use std::marker::PhantomData; use crate::{Decoder, Encoder}; use bytes::{Buf, BufMut, BytesMut}; use serde::{Deserialize, Serialize}; use serde_cbor::Error as CborError; /// A codec for JSON encoding and decoding using serde_cbor /// Enc is the type to encode, Dec is the type to decode /// ``` /// # use futures::{executor, SinkExt, TryStreamExt}; /// # use futures::io::Cursor; /// use serde::{Serialize, Deserialize}; /// use asynchronous_codec::{CborCodec, Framed}; /// /// #[derive(Serialize, Deserialize)] /// struct Something { /// pub data: u16, /// } /// /// async move { /// # let mut buf = vec![]; /// # let stream = Cursor::new(&mut buf); /// // let stream = ... /// let codec = CborCodec::::new(); /// let mut framed = Framed::new(stream, codec); /// /// while let Some(s) = framed.try_next().await.unwrap() { /// println!("{:?}", s.data); /// } /// }; /// ``` #[derive(Debug, PartialEq)] pub struct CborCodec { enc: PhantomData, dec: PhantomData, } /// JSON Codec error enumeration #[derive(Debug)] pub enum CborCodecError { /// IO error Io(IoError), /// JSON error Cbor(CborError), } impl std::fmt::Display for CborCodecError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { CborCodecError::Io(e) => write!(f, "I/O error: {}", e), CborCodecError::Cbor(e) => write!(f, "CBOR error: {}", e), } } } impl std::error::Error for CborCodecError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { CborCodecError::Io(ref e) => Some(e), CborCodecError::Cbor(ref e) => Some(e), } } } impl From for CborCodecError { fn from(e: IoError) -> CborCodecError { CborCodecError::Io(e) } } impl From for CborCodecError { fn from(e: CborError) -> CborCodecError { CborCodecError::Cbor(e) } } impl CborCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { /// Creates a new `CborCodec` with the associated types pub fn new() -> CborCodec { CborCodec { enc: PhantomData, dec: PhantomData, } } } impl Clone for CborCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { /// Clone creates a new instance of the `CborCodec` fn clone(&self) -> CborCodec { CborCodec::new() } } /// Decoder impl parses cbor objects from bytes impl Decoder for CborCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { type Item = Dec; type Error = CborCodecError; fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { // Build deserializer let mut de = serde_cbor::Deserializer::from_slice(&buf); // Attempt deserialization let res: Result = serde::de::Deserialize::deserialize(&mut de); // If we ran out before parsing, return none and try again later let item = match res { Ok(item) => item, Err(e) if e.is_eof() => return Ok(None), Err(e) => return Err(e.into()), }; // Update offset from iterator let offset = de.byte_offset(); // Advance buffer buf.advance(offset); Ok(Some(item)) } } /// Encoder impl encodes object streams to bytes impl Encoder for CborCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { type Item<'a> = Enc; type Error = CborCodecError; fn encode(&mut self, data: Self::Item<'_>, buf: &mut BytesMut) -> Result<(), Self::Error> { // Encode cbor let j = serde_cbor::to_vec(&data)?; // Write to buffer buf.reserve(j.len()); buf.put_slice(&j); Ok(()) } } impl Default for CborCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { fn default() -> Self { Self::new() } } #[cfg(test)] mod test { use bytes::BytesMut; use serde::{Deserialize, Serialize}; use super::CborCodec; use crate::{Decoder, Encoder}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] struct TestStruct { pub name: String, pub data: u16, } #[test] fn cbor_codec_encode_decode() { let mut codec = CborCodec::::new(); let mut buff = BytesMut::new(); let item1 = TestStruct { name: "Test name".to_owned(), data: 16, }; codec.encode(item1.clone(), &mut buff).unwrap(); let item2 = codec.decode(&mut buff).unwrap().unwrap(); assert_eq!(item1, item2); assert_eq!(codec.decode(&mut buff).unwrap(), None); assert_eq!(buff.len(), 0); } #[test] fn cbor_codec_partial_decode() { let mut codec = CborCodec::::new(); let mut buff = BytesMut::new(); let item1 = TestStruct { name: "Test name".to_owned(), data: 34, }; codec.encode(item1, &mut buff).unwrap(); let mut start = buff.clone().split_to(4); assert_eq!(codec.decode(&mut start).unwrap(), None); codec.decode(&mut buff).unwrap().unwrap(); assert_eq!(buff.len(), 0); } #[test] fn cbor_codec_eof_reached() { let mut codec = CborCodec::::new(); let mut buff = BytesMut::new(); let item1 = TestStruct { name: "Test name".to_owned(), data: 34, }; codec.encode(item1.clone(), &mut buff).unwrap(); // Split the buffer into two. let mut buff_start = buff.clone().split_to(4); let buff_end = buff.clone().split_off(4); // Attempt to decode the first half of the buffer. This should return `Ok(None)` and not // advance the buffer. assert_eq!(codec.decode(&mut buff_start).unwrap(), None); assert_eq!(buff_start.len(), 4); // Combine the buffer back together. buff_start.extend(buff_end.iter()); // It should now decode successfully. let item2 = codec.decode(&mut buff).unwrap().unwrap(); assert_eq!(item1, item2); } #[test] fn cbor_codec_decode_error() { let mut codec = CborCodec::::new(); let mut buff = BytesMut::new(); let item1 = TestStruct { name: "Test name".to_owned(), data: 34, }; codec.encode(item1.clone(), &mut buff).unwrap(); // Split the end off the buffer. let mut buff_end = buff.clone().split_off(4); let buff_end_length = buff_end.len(); // Attempting to decode should return an error. assert!(codec.decode(&mut buff_end).is_err()); assert_eq!(buff_end.len(), buff_end_length); } } asynchronous-codec-0.7.0/src/codec/json.rs000064400000000000000000000160761046102023000166330ustar 00000000000000use std::marker::PhantomData; use crate::{Decoder, Encoder}; use bytes::{Buf, BufMut, BytesMut}; use serde::{Deserialize, Serialize}; /// A codec for JSON encoding and decoding using serde_json /// Enc is the type to encode, Dec is the type to decode /// ``` /// # use futures::{executor, SinkExt, TryStreamExt}; /// # use futures::io::Cursor; /// use serde::{Serialize, Deserialize}; /// use asynchronous_codec::{JsonCodec, Framed}; /// /// #[derive(Serialize, Deserialize)] /// struct Something { /// pub data: u16, /// } /// /// async move { /// # let mut buf = vec![]; /// # let stream = Cursor::new(&mut buf); /// // let stream = ... /// let codec = JsonCodec::::new(); /// let mut framed = Framed::new(stream, codec); /// /// while let Some(s) = framed.try_next().await.unwrap() { /// println!("{:?}", s.data); /// } /// }; /// ``` #[derive(Debug, PartialEq)] pub struct JsonCodec { enc: PhantomData, dec: PhantomData, } /// JSON Codec error enumeration #[derive(Debug)] pub enum JsonCodecError { /// IO error Io(std::io::Error), /// JSON error Json(serde_json::Error), } impl std::fmt::Display for JsonCodecError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { JsonCodecError::Io(e) => write!(f, "I/O error: {}", e), JsonCodecError::Json(e) => write!(f, "JSON error: {}", e), } } } impl std::error::Error for JsonCodecError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { JsonCodecError::Io(ref e) => Some(e), JsonCodecError::Json(ref e) => Some(e), } } } impl From for JsonCodecError { fn from(e: std::io::Error) -> JsonCodecError { JsonCodecError::Io(e) } } impl From for JsonCodecError { fn from(e: serde_json::Error) -> JsonCodecError { JsonCodecError::Json(e) } } impl JsonCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { /// Creates a new `JsonCodec` with the associated types pub fn new() -> JsonCodec { JsonCodec { enc: PhantomData, dec: PhantomData, } } } impl Clone for JsonCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { /// Clone creates a new instance of the `JsonCodec` fn clone(&self) -> JsonCodec { JsonCodec::new() } } /// Decoder impl parses json objects from bytes impl Decoder for JsonCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { type Item = Dec; type Error = JsonCodecError; fn decode(&mut self, buf: &mut BytesMut) -> Result, Self::Error> { // Build streaming JSON iterator over data let de = serde_json::Deserializer::from_slice(&buf); let mut iter = de.into_iter::(); // Attempt to fetch an item and generate response let item = match iter.next() { Some(Ok(item)) => item, Some(Err(ref e)) if e.is_eof() => return Ok(None), Some(Err(e)) => return Err(e.into()), None => return Ok(None), }; // Update offset from iterator let offset = iter.byte_offset(); // Advance buffer buf.advance(offset); Ok(Some(item)) } } /// Encoder impl encodes object streams to bytes impl Encoder for JsonCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { type Item<'a> = Enc; type Error = JsonCodecError; fn encode(&mut self, data: Self::Item<'_>, buf: &mut BytesMut) -> Result<(), Self::Error> { // Encode json let j = serde_json::to_string(&data)?; // Write to buffer buf.reserve(j.len()); buf.put_slice(&j.as_bytes()); Ok(()) } } impl Default for JsonCodec where for<'de> Dec: Deserialize<'de> + 'static, for<'de> Enc: Serialize + 'static, { fn default() -> Self { Self::new() } } #[cfg(test)] mod test { use bytes::BytesMut; use serde::{Deserialize, Serialize}; use super::JsonCodec; use crate::{Decoder, Encoder}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] struct TestStruct { pub name: String, pub data: u16, } #[test] fn json_codec_encode_decode() { let mut codec = JsonCodec::::new(); let mut buff = BytesMut::new(); let item1 = TestStruct { name: "Test name".to_owned(), data: 16, }; codec.encode(item1.clone(), &mut buff).unwrap(); let item2 = codec.decode(&mut buff).unwrap().unwrap(); assert_eq!(item1, item2); assert_eq!(codec.decode(&mut buff).unwrap(), None); assert_eq!(buff.len(), 0); } #[test] fn json_codec_partial_decode() { let mut codec = JsonCodec::::new(); let mut buff = BytesMut::new(); let item1 = TestStruct { name: "Test name".to_owned(), data: 34, }; codec.encode(item1, &mut buff).unwrap(); let mut start = buff.clone().split_to(4); assert_eq!(codec.decode(&mut start).unwrap(), None); codec.decode(&mut buff).unwrap().unwrap(); assert_eq!(buff.len(), 0); } #[test] fn json_codec_eof_reached() { let mut codec = JsonCodec::::new(); let mut buff = BytesMut::new(); let item1 = TestStruct { name: "Test name".to_owned(), data: 34, }; codec.encode(item1.clone(), &mut buff).unwrap(); // Split the buffer into two. let mut buff_start = buff.clone().split_to(4); let buff_end = buff.clone().split_off(4); // Attempt to decode the first half of the buffer. This should return `Ok(None)` and not // advance the buffer. assert_eq!(codec.decode(&mut buff_start).unwrap(), None); assert_eq!(buff_start.len(), 4); // Combine the buffer back together. buff_start.extend(buff_end.iter()); // It should now decode successfully. let item2 = codec.decode(&mut buff).unwrap().unwrap(); assert_eq!(item1, item2); } #[test] fn json_codec_decode_error() { let mut codec = JsonCodec::::new(); let mut buff = BytesMut::new(); let item1 = TestStruct { name: "Test name".to_owned(), data: 34, }; codec.encode(item1.clone(), &mut buff).unwrap(); // Split the end off the buffer. let mut buff_end = buff.clone().split_off(4); let buff_end_length = buff_end.len(); // Attempting to decode should return an error. assert!(codec.decode(&mut buff_end).is_err()); assert_eq!(buff_end.len(), buff_end_length); } } asynchronous-codec-0.7.0/src/codec/length.rs000064400000000000000000000054461046102023000171420ustar 00000000000000use crate::{Decoder, Encoder}; use bytes::{Buf, BufMut, Bytes, BytesMut}; use std::io::Error; const U64_LENGTH: usize = std::mem::size_of::(); /// A simple `Codec` implementation sending your data by prefixing it by its length. /// /// # Example /// /// This codec will most likely be used wrapped in another codec like so. /// /// ``` /// use asynchronous_codec::{Decoder, Encoder, LengthCodec}; /// use bytes::{Bytes, BytesMut}; /// use std::io::{Error, ErrorKind}; /// /// pub struct MyStringCodec(LengthCodec); /// /// impl Encoder for MyStringCodec { /// type Item<'a> = String; /// type Error = Error; /// /// fn encode(&mut self, src: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { /// let bytes = Bytes::from(src); /// self.0.encode(bytes, dst) /// } /// } /// /// impl Decoder for MyStringCodec { /// type Item = String; /// type Error = Error; /// /// fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { /// match self.0.decode(src)? { /// Some(bytes) => { /// match String::from_utf8(bytes.to_vec()) { /// Ok(string) => Ok(Some(string)), /// Err(e) => Err(Error::new(ErrorKind::InvalidData, e)) /// } /// }, /// None => Ok(None), /// } /// } /// } /// ``` pub struct LengthCodec; impl Encoder for LengthCodec { type Item<'a> = Bytes; type Error = Error; fn encode(&mut self, src: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { dst.reserve(U64_LENGTH + src.len()); dst.put_u64(src.len() as u64); dst.extend_from_slice(&src); Ok(()) } } impl Decoder for LengthCodec { type Item = Bytes; type Error = Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { if src.len() < U64_LENGTH { return Ok(None); } let mut len_bytes = [0u8; U64_LENGTH]; len_bytes.copy_from_slice(&src[..U64_LENGTH]); let len = u64::from_be_bytes(len_bytes) as usize; if src.len() - U64_LENGTH >= len { // Skip the length header we already read. src.advance(U64_LENGTH); Ok(Some(src.split_to(len).freeze())) } else { Ok(None) } } } #[cfg(test)] mod tests { use super::*; mod decode { use super::*; #[test] fn it_returns_bytes_withouth_length_header() { let mut codec = LengthCodec {}; let mut src = BytesMut::with_capacity(5); src.put(&[0, 0, 0, 0, 0, 0, 0, 3u8, 1, 2, 3, 4][..]); let item = codec.decode(&mut src).unwrap(); assert!(item == Some(Bytes::from(&[1u8, 2, 3][..]))); } } } asynchronous-codec-0.7.0/src/codec/lines.rs000064400000000000000000000026121046102023000167630ustar 00000000000000use crate::{Decoder, Encoder}; use bytes::{BufMut, BytesMut}; use memchr::memchr; use std::io::{Error, ErrorKind}; /// A simple `Codec` implementation that splits up data into lines. /// /// ```rust /// # futures::executor::block_on(async move { /// use futures::stream::TryStreamExt; // for lines.try_next() /// use asynchronous_codec::{FramedRead, LinesCodec}; /// /// let input = "hello\nworld\nthis\nis\ndog\n".as_bytes(); /// let mut lines = FramedRead::new(input, LinesCodec); /// while let Some(line) = lines.try_next().await? { /// println!("{}", line); /// } /// # Ok::<_, std::io::Error>(()) /// # }).unwrap(); /// ``` pub struct LinesCodec; impl Encoder for LinesCodec { type Item<'a> = String; type Error = Error; fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { dst.reserve(item.len()); dst.put(item.as_bytes()); Ok(()) } } impl Decoder for LinesCodec { type Item = String; type Error = Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { match memchr(b'\n', src) { Some(pos) => { let buf = src.split_to(pos + 1); String::from_utf8(buf.to_vec()) .map(Some) .map_err(|e| Error::new(ErrorKind::InvalidData, e)) } _ => Ok(None), } } } asynchronous-codec-0.7.0/src/codec/mod.rs000064400000000000000000000005451046102023000164330ustar 00000000000000mod bytes; pub use self::bytes::BytesCodec; mod length; pub use self::length::LengthCodec; mod lines; pub use self::lines::LinesCodec; #[cfg(feature = "json")] mod json; #[cfg(feature = "json")] pub use self::json::{JsonCodec, JsonCodecError}; #[cfg(feature = "cbor")] mod cbor; #[cfg(feature = "cbor")] pub use self::cbor::{CborCodec, CborCodecError}; asynchronous-codec-0.7.0/src/decoder.rs000064400000000000000000000027601046102023000162050ustar 00000000000000use super::framed_write::FramedWrite2; use super::fuse::Fuse; use bytes::BytesMut; use std::io::Error; /// Decoding of frames via buffers, for use with `FramedRead`. pub trait Decoder { /// The type of items returned by `decode` type Item; /// The type of decoding errors. type Error: From; /// Decode an item from the src `BytesMut` into an item fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error>; /// Called when the input stream reaches EOF, signaling a last attempt to decode /// /// # Notes /// /// The default implementation of this method invokes the `Decoder::decode` method. fn decode_eof(&mut self, src: &mut BytesMut) -> Result, Self::Error> { self.decode(src) } } impl Decoder for Fuse { type Item = U::Item; type Error = U::Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { self.u.decode(src) } fn decode_eof(&mut self, src: &mut BytesMut) -> Result, Self::Error> { self.u.decode_eof(src) } } impl Decoder for FramedWrite2 { type Item = T::Item; type Error = T::Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { self.inner.decode(src) } fn decode_eof(&mut self, src: &mut BytesMut) -> Result, Self::Error> { self.inner.decode_eof(src) } } asynchronous-codec-0.7.0/src/encoder.rs000064400000000000000000000025451046102023000162200ustar 00000000000000use super::fuse::Fuse; use bytes::BytesMut; use std::io::Error; /// Encoding of messages as bytes, for use with `FramedWrite`. pub trait Encoder { /// The type of items consumed by `encode` type Item<'a>; /// The type of encoding errors. type Error: From; /// Encodes an item into the `BytesMut` provided by dst. fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error>; } impl Encoder for Fuse { type Item<'a> = U::Item<'a>; type Error = U::Error; fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { self.u.encode(item, dst) } } #[cfg(test)] mod tests { use super::*; use crate::FramedWrite; use futures::executor::block_on; use futures_util::SinkExt; #[test] fn can_use_borrowed_data() { let mut buf = Vec::new(); let mut write = FramedWrite::new(&mut buf, BorrowedCodec); block_on(write.send(&[1, 2, 3, 4])).unwrap(); assert_eq!(buf, vec![1, 2, 3, 4]) } struct BorrowedCodec; impl Encoder for BorrowedCodec { type Item<'a> = &'a [u8]; type Error = Error; fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> { dst.extend_from_slice(item); Ok(()) } } } asynchronous-codec-0.7.0/src/framed.rs000064400000000000000000000147421046102023000160410ustar 00000000000000use super::framed_read::{framed_read_2, FramedRead2}; use super::framed_write::{framed_write_2, FramedWrite2}; use super::fuse::Fuse; use super::{Decoder, Encoder}; use bytes::BytesMut; use futures_sink::Sink; use futures_util::io::{AsyncRead, AsyncWrite}; use futures_util::stream::{Stream, TryStreamExt}; use pin_project_lite::pin_project; use std::marker::Unpin; use std::ops::{Deref, DerefMut}; use std::pin::Pin; use std::task::{Context, Poll}; pin_project! { /// A unified `Stream` and `Sink` interface to an underlying I/O object, /// using the `Encoder` and `Decoder` traits to encode and decode frames. /// /// # Example /// ``` /// use bytes::Bytes; /// use futures::{SinkExt, TryStreamExt}; /// use futures::io::Cursor; /// use asynchronous_codec::{BytesCodec, Framed}; /// /// # futures::executor::block_on(async move { /// let cur = Cursor::new(vec![0u8; 12]); /// let mut framed = Framed::new(cur, BytesCodec {}); /// /// // Send bytes to `buf` through the `BytesCodec` /// let bytes = Bytes::from("Hello world!"); /// framed.send(bytes).await?; /// /// // Drop down to the underlying I/O stream. /// let cur = framed.into_inner(); /// assert_eq!(cur.get_ref(), b"Hello world!"); /// # Ok::<_, std::io::Error>(()) /// # }).unwrap(); /// ``` #[derive(Debug)] pub struct Framed { #[pin] inner: FramedRead2>>, } } impl Deref for Framed { type Target = T; fn deref(&self) -> &T { &self.inner } } impl DerefMut for Framed { fn deref_mut(&mut self) -> &mut T { &mut self.inner } } impl Framed where T: AsyncRead + AsyncWrite, U: Decoder + Encoder, { /// Creates a new `Framed` transport with the given codec. /// A codec is a type which implements `Decoder` and `Encoder`. pub fn new(inner: T, codec: U) -> Self { Self { inner: framed_read_2(framed_write_2(Fuse::new(inner, codec), None), None), } } /// Creates a new `Framed` from [`FramedParts`]. /// /// See also [`Framed::into_parts`]. pub fn from_parts( FramedParts { io, codec, write_buffer, read_buffer, .. }: FramedParts, ) -> Self { let framed_write = framed_write_2(Fuse::new(io, codec), Some(write_buffer)); let framed_read = framed_read_2(framed_write, Some(read_buffer)); Self { inner: framed_read } } /// Consumes the `Framed`, returning its parts, such that a new /// `Framed` may be constructed, possibly with a different codec. /// /// See also [`Framed::from_parts`]. pub fn into_parts(self) -> FramedParts { let (framed_write, read_buffer) = self.inner.into_parts(); let (fuse, write_buffer) = framed_write.into_parts(); FramedParts { io: fuse.t, codec: fuse.u, read_buffer, write_buffer, _priv: (), } } /// Consumes the `Framed`, returning its underlying I/O stream. /// /// Note that data that has already been read or written but not yet /// consumed by the decoder or flushed, respectively, is dropped. /// To retain any such potentially buffered data, use [`Framed::into_parts()`]. pub fn into_inner(self) -> T { self.into_parts().io } /// Returns a reference to the underlying codec wrapped by /// `Framed`. /// /// Note that care should be taken to not tamper with the underlying codec /// as it may corrupt the stream of frames otherwise being worked with. pub fn codec(&self) -> &U { &self.inner.u } /// Returns a mutable reference to the underlying codec wrapped by /// `Framed`. /// /// Note that care should be taken to not tamper with the underlying codec /// as it may corrupt the stream of frames otherwise being worked with. pub fn codec_mut(&mut self) -> &mut U { &mut self.inner.u } /// Returns a reference to the read buffer. pub fn read_buffer(&self) -> &BytesMut { self.inner.buffer() } /// High-water mark for writes, in bytes /// /// See [`FramedWrite::send_high_water_mark`]. pub fn send_high_water_mark(&self) -> usize { self.inner.high_water_mark } /// Sets high-water mark for writes, in bytes /// /// See [`FramedWrite::set_send_high_water_mark`]. pub fn set_send_high_water_mark(&mut self, hwm: usize) { self.inner.high_water_mark = hwm; } } impl Stream for Framed where T: AsyncRead + Unpin, U: Decoder, { type Item = Result; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.inner.try_poll_next_unpin(cx) } } impl Sink> for Framed where T: AsyncWrite + Unpin, U: Encoder, { type Error = U::Error; fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_ready(cx) } fn start_send(self: Pin<&mut Self>, item: U::Item<'_>) -> Result<(), Self::Error> { self.project().inner.start_send(item) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_flush(cx) } fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_close(cx) } } /// The parts obtained from [`Framed::into_parts`]. pub struct FramedParts { /// The underlying I/O stream. pub io: T, /// The codec used for encoding and decoding frames. pub codec: U, /// The remaining read buffer, containing data that has been /// read from `io` but not yet consumed by the codec's decoder. pub read_buffer: BytesMut, /// The remaining write buffer, containing framed data that has been /// buffered but not yet flushed to `io`. pub write_buffer: BytesMut, /// Keep the constructor private. _priv: (), } impl FramedParts { /// Changes the codec used in this `FramedParts`. pub fn map_codec(self, f: F) -> FramedParts where F: FnOnce(U) -> V, { FramedParts { io: self.io, codec: f(self.codec), read_buffer: self.read_buffer, write_buffer: self.write_buffer, _priv: (), } } } asynchronous-codec-0.7.0/src/framed_read.rs000064400000000000000000000164501046102023000170320ustar 00000000000000use super::fuse::Fuse; use super::Decoder; use bytes::BytesMut; use futures_sink::Sink; use futures_util::io::AsyncRead; use futures_util::ready; use futures_util::stream::{Stream, TryStreamExt}; use pin_project_lite::pin_project; use std::io; use std::marker::Unpin; use std::ops::{Deref, DerefMut}; use std::pin::Pin; use std::task::{Context, Poll}; /// A `Stream` of messages decoded from an `AsyncRead`. /// /// # Example /// ``` /// use asynchronous_codec::{BytesCodec, FramedRead}; /// use futures::TryStreamExt; /// use bytes::{Bytes}; /// /// let buf = [3u8; 3]; /// let mut framed = FramedRead::new(&buf[..], BytesCodec); /// /// # futures::executor::block_on(async move { /// if let Some(bytes) = framed.try_next().await? { /// assert_eq!(bytes, Bytes::copy_from_slice(&buf[..])); /// } /// # Ok::<_, std::io::Error>(()) /// # }).unwrap(); /// ``` #[derive(Debug)] pub struct FramedRead { inner: FramedRead2>, } impl Deref for FramedRead { type Target = T; fn deref(&self) -> &T { &self.inner } } impl DerefMut for FramedRead { fn deref_mut(&mut self) -> &mut T { &mut self.inner } } impl FramedRead where T: AsyncRead, D: Decoder, { /// Creates a new `FramedRead` transport with the given `Decoder`. pub fn new(inner: T, decoder: D) -> Self { Self { inner: framed_read_2(Fuse::new(inner, decoder), None), } } /// Creates a new `FramedRead` from [`FramedReadParts`]. /// /// See also [`FramedRead::into_parts`]. pub fn from_parts( FramedReadParts { io, decoder, buffer, .. }: FramedReadParts, ) -> Self { Self { inner: framed_read_2(Fuse::new(io, decoder), Some(buffer)), } } /// Consumes the `FramedRead`, returning its parts such that a /// new `FramedRead` may be constructed, possibly with a different decoder. /// /// See also [`FramedRead::from_parts`]. pub fn into_parts(self) -> FramedReadParts { let (fuse, buffer) = self.inner.into_parts(); FramedReadParts { io: fuse.t, decoder: fuse.u, buffer, _priv: (), } } /// Consumes the `FramedRead`, returning its underlying I/O stream. /// /// Note that data that has already been read but not yet consumed /// by the decoder is dropped. To retain any such potentially /// buffered data, use [`FramedRead::into_parts()`]. pub fn into_inner(self) -> T { self.into_parts().io } /// Returns a reference to the underlying decoder. /// /// Note that care should be taken to not tamper with the underlying decoder /// as it may corrupt the stream of frames otherwise being worked with. pub fn decoder(&self) -> &D { &self.inner.u } /// Returns a mutable reference to the underlying decoder. /// /// Note that care should be taken to not tamper with the underlying decoder /// as it may corrupt the stream of frames otherwise being worked with. pub fn decoder_mut(&mut self) -> &mut D { &mut self.inner.u } /// Returns a reference to the read buffer. pub fn read_buffer(&self) -> &BytesMut { &self.inner.buffer } } impl Stream for FramedRead where T: AsyncRead + Unpin, D: Decoder, { type Item = Result; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.inner.try_poll_next_unpin(cx) } } pin_project! { #[derive(Debug)] pub struct FramedRead2 { #[pin] inner: T, buffer: BytesMut, } } impl Deref for FramedRead2 { type Target = T; fn deref(&self) -> &T { &self.inner } } impl DerefMut for FramedRead2 { fn deref_mut(&mut self) -> &mut T { &mut self.inner } } const INITIAL_CAPACITY: usize = 8 * 1024; pub fn framed_read_2(inner: T, buffer: Option) -> FramedRead2 { FramedRead2 { inner, buffer: buffer.unwrap_or_else(|| BytesMut::with_capacity(INITIAL_CAPACITY)), } } impl Stream for FramedRead2 where T: AsyncRead + Decoder + Unpin, { type Item = Result; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = &mut *self; if let Some(item) = this.inner.decode(&mut this.buffer)? { return Poll::Ready(Some(Ok(item))); } let mut buf = [0u8; INITIAL_CAPACITY]; loop { let n = ready!(Pin::new(&mut this.inner).poll_read(cx, &mut buf))?; this.buffer.extend_from_slice(&buf[..n]); let ended = n == 0; match this.inner.decode(&mut this.buffer)? { Some(item) => return Poll::Ready(Some(Ok(item))), None if ended => { if this.buffer.is_empty() { return Poll::Ready(None); } else { match this.inner.decode_eof(&mut this.buffer)? { Some(item) => return Poll::Ready(Some(Ok(item))), None if this.buffer.is_empty() => return Poll::Ready(None), None => { return Poll::Ready(Some(Err(io::Error::new( io::ErrorKind::UnexpectedEof, "bytes remaining in stream", ) .into()))); } } } } _ => continue, } } } } impl Sink for FramedRead2 where T: Sink + Unpin, { type Error = T::Error; fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_ready(cx) } fn start_send(self: Pin<&mut Self>, item: I) -> Result<(), Self::Error> { self.project().inner.start_send(item) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_flush(cx) } fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_close(cx) } } impl FramedRead2 { pub fn into_parts(self) -> (T, BytesMut) { (self.inner, self.buffer) } pub fn buffer(&self) -> &BytesMut { &self.buffer } } /// The parts obtained from (FramedRead::into_parts). pub struct FramedReadParts { /// The underlying I/O stream. pub io: T, /// The frame decoder. pub decoder: D, /// The buffer of data that has been read from `io` but not /// yet consumed by `decoder`. pub buffer: BytesMut, /// Keep the constructor private. _priv: (), } impl FramedReadParts { /// Changes the decoder in `FramedReadParts`. pub fn map_decoder(self, f: F) -> FramedReadParts where E: Decoder, F: FnOnce(D) -> E, { FramedReadParts { io: self.io, decoder: f(self.decoder), buffer: self.buffer, _priv: (), } } } asynchronous-codec-0.7.0/src/framed_write.rs000064400000000000000000000215251046102023000172500ustar 00000000000000use super::fuse::Fuse; use super::Encoder; use bytes::{Buf, BytesMut}; use futures_sink::Sink; use futures_util::io::{AsyncRead, AsyncWrite}; use futures_util::ready; use pin_project_lite::pin_project; use std::io::{Error, ErrorKind}; use std::marker::Unpin; use std::ops::{Deref, DerefMut}; use std::pin::Pin; use std::task::{Context, Poll}; pin_project! { /// A `Sink` of frames encoded to an `AsyncWrite`. /// /// # Example /// ``` /// use bytes::Bytes; /// use asynchronous_codec::{FramedWrite, BytesCodec}; /// use futures::SinkExt; /// /// # futures::executor::block_on(async move { /// let mut buf = Vec::new(); /// let mut framed = FramedWrite::new(&mut buf, BytesCodec {}); /// /// let bytes = Bytes::from("Hello World!"); /// framed.send(bytes.clone()).await?; /// /// assert_eq!(&buf[..], &bytes[..]); /// # Ok::<_, std::io::Error>(()) /// # }).unwrap(); /// ``` #[derive(Debug)] pub struct FramedWrite { #[pin] inner: FramedWrite2>, } } impl FramedWrite where T: AsyncWrite, E: Encoder, { /// Creates a new `FramedWrite` transport with the given `Encoder`. pub fn new(inner: T, encoder: E) -> Self { Self { inner: framed_write_2(Fuse::new(inner, encoder), None), } } /// Creates a new `FramedWrite` from [`FramedWriteParts`]. /// /// See also [`FramedWrite::into_parts`]. pub fn from_parts( FramedWriteParts { io, encoder, buffer, .. }: FramedWriteParts, ) -> Self { Self { inner: framed_write_2(Fuse::new(io, encoder), Some(buffer)), } } /// High-water mark for writes, in bytes /// /// The send *high-water mark* prevents the `FramedWrite` /// from accepting additional messages to send when its /// buffer exceeds this length, in bytes. Attempts to enqueue /// additional messages will be deferred until progress is /// made on the underlying `AsyncWrite`. This applies /// back-pressure on fast senders and prevents unbounded /// buffer growth. /// /// See [`set_send_high_water_mark()`](#method.set_send_high_water_mark). pub fn send_high_water_mark(&self) -> usize { self.inner.high_water_mark } /// Sets high-water mark for writes, in bytes /// /// The send *high-water mark* prevents the `FramedWrite` /// from accepting additional messages to send when its /// buffer exceeds this length, in bytes. Attempts to enqueue /// additional messages will be deferred until progress is /// made on the underlying `AsyncWrite`. This applies /// back-pressure on fast senders and prevents unbounded /// buffer growth. /// /// The default high-water mark is 2^17 bytes. Applications /// which desire low latency may wish to reduce this value. /// There is little point to increasing this value beyond /// your socket's `SO_SNDBUF` size. On linux, this defaults /// to 212992 bytes but is user-adjustable. pub fn set_send_high_water_mark(&mut self, hwm: usize) { self.inner.high_water_mark = hwm; } /// Consumes the `FramedWrite`, returning its parts such that /// a new `FramedWrite` may be constructed, possibly with a different encoder. /// /// See also [`FramedWrite::from_parts`]. pub fn into_parts(self) -> FramedWriteParts { let (fuse, buffer) = self.inner.into_parts(); FramedWriteParts { io: fuse.t, encoder: fuse.u, buffer, _priv: (), } } /// Consumes the `FramedWrite`, returning its underlying I/O stream. /// /// Note that data that has already been written but not yet flushed /// is dropped. To retain any such potentially buffered data, use /// [`FramedWrite::into_parts()`]. pub fn into_inner(self) -> T { self.into_parts().io } /// Returns a reference to the underlying encoder. /// /// Note that care should be taken to not tamper with the underlying encoder /// as it may corrupt the stream of frames otherwise being worked with. pub fn encoder(&self) -> &E { &self.inner.u } /// Returns a mutable reference to the underlying encoder. /// /// Note that care should be taken to not tamper with the underlying encoder /// as it may corrupt the stream of frames otherwise being worked with. pub fn encoder_mut(&mut self) -> &mut E { &mut self.inner.u } } impl Sink> for FramedWrite where T: AsyncWrite + Unpin, E: Encoder, { type Error = E::Error; fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_ready(cx) } fn start_send(self: Pin<&mut Self>, item: E::Item<'_>) -> Result<(), Self::Error> { self.project().inner.start_send(item) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_flush(cx) } fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().inner.poll_close(cx) } } impl Deref for FramedWrite { type Target = T; fn deref(&self) -> &T { &self.inner } } impl DerefMut for FramedWrite { fn deref_mut(&mut self) -> &mut T { &mut self.inner } } pin_project! { #[derive(Debug)] pub struct FramedWrite2 { #[pin] pub inner: T, pub high_water_mark: usize, buffer: BytesMut, } } impl Deref for FramedWrite2 { type Target = T; fn deref(&self) -> &T { &self.inner } } impl DerefMut for FramedWrite2 { fn deref_mut(&mut self) -> &mut T { &mut self.inner } } // 2^17 bytes, which is slightly over 60% of the default // TCP send buffer size (SO_SNDBUF) const DEFAULT_SEND_HIGH_WATER_MARK: usize = 131072; pub fn framed_write_2(inner: T, buffer: Option) -> FramedWrite2 { FramedWrite2 { inner, high_water_mark: DEFAULT_SEND_HIGH_WATER_MARK, buffer: buffer.unwrap_or_else(|| BytesMut::with_capacity(1028 * 8)), } } impl AsyncRead for FramedWrite2 { fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { self.project().inner.poll_read(cx, buf) } } impl Sink> for FramedWrite2 where T: AsyncWrite + Encoder + Unpin, { type Error = T::Error; fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let this = &mut *self; while this.buffer.len() >= this.high_water_mark { let num_write = ready!(Pin::new(&mut this.inner).poll_write(cx, &this.buffer))?; if num_write == 0 { return Poll::Ready(Err(err_eof().into())); } this.buffer.advance(num_write); } Poll::Ready(Ok(())) } fn start_send(mut self: Pin<&mut Self>, item: T::Item<'_>) -> Result<(), Self::Error> { let this = &mut *self; this.inner.encode(item, &mut this.buffer) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let mut this = self.project(); while !this.buffer.is_empty() { let num_write = ready!(Pin::new(&mut this.inner).poll_write(cx, &this.buffer))?; if num_write == 0 { return Poll::Ready(Err(err_eof().into())); } this.buffer.advance(num_write); } this.inner.poll_flush(cx).map_err(Into::into) } fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { ready!(self.as_mut().poll_flush(cx))?; self.project().inner.poll_close(cx).map_err(Into::into) } } impl FramedWrite2 { pub fn into_parts(self) -> (T, BytesMut) { (self.inner, self.buffer) } } fn err_eof() -> Error { Error::new(ErrorKind::UnexpectedEof, "End of file") } /// The parts obtained from [`FramedWrite::into_parts`]. pub struct FramedWriteParts { /// The underlying I/O stream. pub io: T, /// The frame encoder. pub encoder: E, /// The framed data that has been buffered but not yet flushed to `io`. pub buffer: BytesMut, /// Keep the constructor private. _priv: (), } impl FramedWriteParts { /// Changes the encoder used in `FramedWriteParts`. pub fn map_encoder(self, f: F) -> FramedWriteParts where G: Encoder, F: FnOnce(E) -> G, { FramedWriteParts { io: self.io, encoder: f(self.encoder), buffer: self.buffer, _priv: (), } } } asynchronous-codec-0.7.0/src/fuse.rs000064400000000000000000000026111046102023000155350ustar 00000000000000use futures_util::io::{AsyncRead, AsyncWrite}; use pin_project_lite::pin_project; use std::io::Error; use std::marker::Unpin; use std::ops::{Deref, DerefMut}; use std::pin::Pin; use std::task::{Context, Poll}; pin_project! { #[derive(Debug)] pub(crate) struct Fuse { #[pin] pub t: T, pub u: U, } } impl Fuse { pub(crate) fn new(t: T, u: U) -> Self { Self { t, u } } } impl Deref for Fuse { type Target = T; fn deref(&self) -> &T { &self.t } } impl DerefMut for Fuse { fn deref_mut(&mut self) -> &mut T { &mut self.t } } impl AsyncRead for Fuse { fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { self.project().t.poll_read(cx, buf) } } impl AsyncWrite for Fuse { fn poll_write( self: Pin<&mut Self>, cx: &mut Context, buf: &[u8], ) -> Poll> { self.project().t.poll_write(cx, buf) } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().t.poll_flush(cx) } fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { self.project().t.poll_close(cx) } } asynchronous-codec-0.7.0/src/lib.rs000064400000000000000000000024301046102023000153400ustar 00000000000000#![deny(missing_docs)] //! Utilities for encoding and decoding frames using `async/await`. //! //! Contains adapters to go from streams of bytes, [`AsyncRead`](futures::io::AsyncRead) //! and [`AsyncWrite`](futures::io::AsyncWrite), to framed streams implementing [`Sink`](futures::Sink) and [`Stream`](futures::Stream). //! Framed streams are also known as `transports`. //! //! ``` //! # futures::executor::block_on(async move { //! use futures::TryStreamExt; //! use futures::io::Cursor; //! use asynchronous_codec::{LinesCodec, Framed}; //! //! let io = Cursor::new(Vec::new()); //! let mut framed = Framed::new(io, LinesCodec); //! //! while let Some(line) = framed.try_next().await? { //! dbg!(line); //! } //! # Ok::<_, std::io::Error>(()) //! # }).unwrap(); //! ``` mod codec; pub use bytes::{Bytes, BytesMut}; pub use codec::{BytesCodec, LengthCodec, LinesCodec}; #[cfg(feature = "cbor")] pub use codec::{CborCodec, CborCodecError}; #[cfg(feature = "json")] pub use codec::{JsonCodec, JsonCodecError}; mod decoder; pub use decoder::Decoder; mod encoder; pub use encoder::Encoder; mod framed; pub use framed::{Framed, FramedParts}; mod framed_read; pub use framed_read::{FramedRead, FramedReadParts}; mod framed_write; pub use framed_write::{FramedWrite, FramedWriteParts}; mod fuse; asynchronous-codec-0.7.0/tests/bytes.rs000064400000000000000000000007271046102023000163020ustar 00000000000000use asynchronous_codec::{BytesCodec, Framed}; use futures::io::Cursor; use futures::{executor, TryStreamExt}; #[test] fn decodes() { let mut buf = [0u8; 32]; let expected = buf; let cur = Cursor::new(&mut buf[..]); let mut framed = Framed::new(cur, BytesCodec {}); let read = executor::block_on(framed.try_next()).unwrap().unwrap(); assert_eq!(&read[..], &expected[..]); assert!(executor::block_on(framed.try_next()).unwrap().is_none()); } asynchronous-codec-0.7.0/tests/framed_read.rs000064400000000000000000000044641046102023000174070ustar 00000000000000use asynchronous_codec::{BytesMut, Decoder, FramedRead, LinesCodec}; use futures::executor; use futures::stream::StreamExt; use futures::AsyncRead; use std::io; use std::pin::Pin; use std::task::{Context, Poll}; // Sends two lines at once, then nothing else forever struct MockBurstySender { sent: bool, } impl AsyncRead for MockBurstySender { fn poll_read( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { const MESSAGES: &[u8] = b"one\ntwo\n"; if !self.sent && buf.len() >= MESSAGES.len() { self.sent = true; buf[0..MESSAGES.len()].clone_from_slice(MESSAGES); Poll::Ready(Ok(MESSAGES.len())) } else { Poll::Pending } } } #[test] fn line_read_multi() { let io = MockBurstySender { sent: false }; let mut framed = FramedRead::new(io, LinesCodec {}); let one = executor::block_on(framed.next()).unwrap().unwrap(); assert_eq!(one, "one\n"); let two = executor::block_on(framed.next()).unwrap().unwrap(); assert_eq!(two, "two\n"); } struct OneByteAtATime<'a> { input: &'a [u8], } impl AsyncRead for OneByteAtATime<'_> { fn poll_read( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { if self.input.is_empty() { Poll::Ready(Ok(0)) } else { buf[0] = self.input[0]; self.input = &self.input[1..]; Poll::Ready(Ok(1)) } } } /// A decoder that only returns `a` characters from the input. struct AllTheAs; impl Decoder for AllTheAs { type Item = char; type Error = io::Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { while !src.is_empty() { let buf = src.split_to(1); let c = char::from(buf[0]); if c == 'a' { return Ok(Some(c)); } } Ok(None) } } #[test] fn read_few_messages() { let string: &[u8] = b"aabbbabbbabbbabb"; let input = OneByteAtATime { input: string }; let mut framed = FramedRead::new(input, AllTheAs); for _ in 0..5 { let item = executor::block_on(framed.next()).unwrap().unwrap(); assert_eq!(item, 'a'); } } asynchronous-codec-0.7.0/tests/framed_write.rs000064400000000000000000000055461046102023000176300ustar 00000000000000use asynchronous_codec::{Bytes, BytesCodec, FramedWrite, LinesCodec}; use core::iter::Iterator; use futures::io::{AsyncWrite, Cursor}; use futures::sink::SinkExt; use futures::{executor, stream, stream::StreamExt}; use std::pin::Pin; use std::task::{Context, Poll}; // An iterator which outputs a single zero byte up to limit times struct ZeroBytes { pub count: usize, pub limit: usize, } impl Iterator for ZeroBytes { type Item = Bytes; fn next(&mut self) -> Option { if self.count >= self.limit { None } else { self.count += 1; Some(Bytes::from_static(b"\0")) } } } // An AsyncWrite which is always ready and just consumes the data struct AsyncWriteNull { // number of poll_write calls pub num_poll_write: usize, // size of the last poll_write pub last_write_size: usize, } impl AsyncWrite for AsyncWriteNull { fn poll_write( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { self.num_poll_write += 1; self.last_write_size = buf.len(); Poll::Ready(Ok(buf.len())) } fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } } #[test] fn line_write() { let curs = Cursor::new(vec![0u8; 16]); let mut framer = FramedWrite::new(curs, LinesCodec {}); executor::block_on(framer.send("Hello\n".to_owned())).unwrap(); executor::block_on(framer.send("World\n".to_owned())).unwrap(); let curs = framer.into_inner(); assert_eq!(&curs.get_ref()[0..12], b"Hello\nWorld\n"); assert_eq!(curs.position(), 12); } #[test] fn line_write_to_eof() { let mut buf = [0u8; 16]; let curs = Cursor::new(&mut buf[..]); let mut framer = FramedWrite::new(curs, LinesCodec {}); let _err = executor::block_on(framer.send("This will fill up the buffer\n".to_owned())).unwrap_err(); let curs = framer.into_inner(); assert_eq!(curs.position(), 16); assert_eq!(&curs.get_ref()[0..16], b"This will fill u"); } #[test] fn send_high_water_mark() { // stream will output 999 bytes, 1 at at a time, and will always be ready let mut stream = stream::iter(ZeroBytes { count: 0, limit: 999, }) .map(Ok); // sink will eat whatever it receives let io = AsyncWriteNull { num_poll_write: 0, last_write_size: 0, }; // expect two sends let mut framer = FramedWrite::new(io, BytesCodec {}); framer.set_send_high_water_mark(500); executor::block_on(framer.send_all(&mut stream)).unwrap(); let io = framer.into_inner(); assert_eq!(io.num_poll_write, 2); assert_eq!(io.last_write_size, 499); } asynchronous-codec-0.7.0/tests/length_delimited.rs000064400000000000000000000016201046102023000204460ustar 00000000000000use asynchronous_codec::{Bytes, Framed, LengthCodec}; use futures::io::Cursor; use futures::{executor, SinkExt, StreamExt}; #[test] fn same_msgs_are_received_as_were_sent() { let cur = Cursor::new(vec![0; 256]); let mut framed = Framed::new(cur, LengthCodec {}); let send_msgs = async { framed.send(Bytes::from("msg1")).await.unwrap(); framed.send(Bytes::from("msg2")).await.unwrap(); framed.send(Bytes::from("msg3")).await.unwrap(); }; executor::block_on(send_msgs); let mut cur = framed.into_inner(); cur.set_position(0); let framed = Framed::new(cur, LengthCodec {}); let recv_msgs = framed .take(3) .map(|res| res.unwrap()) .map(|buf| String::from_utf8(buf.to_vec()).unwrap()) .collect::>(); let msgs: Vec = executor::block_on(recv_msgs); assert!(msgs == vec!["msg1", "msg2", "msg3"]); } asynchronous-codec-0.7.0/tests/lines.rs000064400000000000000000000010501046102023000162540ustar 00000000000000use asynchronous_codec::{FramedRead, LinesCodec}; use futures::io::Cursor; use futures::{executor, TryStreamExt}; #[test] fn it_works() { let buf = "Hello\nWorld\nError".to_owned(); let cur = Cursor::new(buf); let mut framed = FramedRead::new(cur, LinesCodec {}); let next = executor::block_on(framed.try_next()).unwrap().unwrap(); assert_eq!(next, "Hello\n"); let next = executor::block_on(framed.try_next()).unwrap().unwrap(); assert_eq!(next, "World\n"); assert!(executor::block_on(framed.try_next()).is_err()); }