From bc03131bf7e90f83c36f086090ef6657f40e847c Mon Sep 17 00:00:00 2001 From: Jared Lunde Date: Sun, 3 May 2026 14:26:34 -0500 Subject: [PATCH] add monoio encoding --- Cargo.lock | 70 +++++++++++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 6 ++++- README.md | 20 +++++++++++++++ src/codec.rs | 32 ++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 51b15b8..8bbbce1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,6 +43,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "auto-const-array" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd73835ad7deb4bd2b389e6f10333b143f025d607c55ca04c66a0bcc6bb2fc6d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -57,13 +68,14 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "beyond-resp" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bytes", "divan", "futures-util", "itoa", "memchr", + "monoio-codec", "ryu", "testcontainers", "testcontainers-modules", @@ -140,6 +152,12 @@ version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.11.1" @@ -466,6 +484,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "getrandom" version = "0.2.17" @@ -614,7 +641,7 @@ dependencies = [ "hyper", "libc", "pin-project-lite", - "socket2", + "socket2 0.6.3", "tokio", "tower-service", "tracing", @@ -862,6 +889,33 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "monoio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd0f8bcde87b1949f95338b547543fcab187bc7e7a5024247e359a5e828ba6a" +dependencies = [ + "auto-const-array", + "bytes", + "fxhash", + "libc", + "memchr", + "pin-project-lite", + "socket2 0.5.10", + "windows-sys 0.48.0", +] + +[[package]] +name = "monoio-codec" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c0e52577d2f766a87e7d60df9a635a35aecf37962e801ca07c73666b95b620" +dependencies = [ + "bytes", + "monoio", + "tokio-util", +] + [[package]] name = "num-conv" version = "0.2.1" @@ -1303,6 +1357,16 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.3" @@ -1495,7 +1559,7 @@ dependencies = [ "libc", "mio", "pin-project-lite", - "socket2", + "socket2 0.6.3", "tokio-macros", "windows-sys 0.61.2", ] diff --git a/Cargo.toml b/Cargo.toml index a4c0860..c76d015 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,13 @@ [package] name = "beyond-resp" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = "RESP2/RESP3 wire protocol codec" license = "MIT" +[features] +monoio = ["dep:monoio-codec"] + [dependencies] bytes = "1" tokio-util = { version = "0.7", default-features = false, features = ["codec"] } @@ -12,6 +15,7 @@ thiserror = "2" itoa = "1" ryu = "1" memchr = "2" +monoio-codec = { version = "0.3", optional = true } [dev-dependencies] tokio = { version = "1", features = ["rt", "macros", "io-util", "net", "rt-multi-thread"] } diff --git a/README.md b/README.md index ecb2117..30b546d 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,13 @@ Frame and parse RESP2/RESP3 over any async byte stream beyond-resp = "0.1" ``` +Enable monoio support: + +```toml +[dependencies] +beyond-resp = { version = "0.1", features = ["monoio"] } +``` + ## Quick Start ```rust @@ -50,6 +57,19 @@ if let Some(response) = framed.next().await { } ``` +With a monoio transport: + +```rust +use beyond_resp::{RespCodec, Value}; +use monoio::net::TcpStream; +use monoio_codec::Decoder; // brings .framed() into scope + +let stream = TcpStream::connect("127.0.0.1:6379").await?; +let mut framed = RespCodec::resp2().framed(stream); +``` + +`monoio_codec::Decoder` returns `Decoded` — `Decoded::Some(v)` when a frame is ready, `Decoded::Insufficient` when more bytes are needed. + ## Protocol Version `RespCodec::resp2()` and `RespCodec::resp3()` select the version at construction. Switch mid-stream after a `HELLO 3` handshake: diff --git a/src/codec.rs b/src/codec.rs index feaa634..61e2c34 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -109,3 +109,35 @@ impl Encoder<&Value> for RespCodec { Ok(()) } } + +#[cfg(feature = "monoio")] +impl monoio_codec::Decoder for RespCodec { + type Item = Value; + type Error = RespError; + + fn decode(&mut self, src: &mut BytesMut) -> Result, RespError> { + if src.is_empty() { + return Ok(monoio_codec::Decoded::Insufficient); + } + if src.len() > self.max_frame_bytes { + return Err(RespError::too_large(self.max_frame_bytes)); + } + match parse::frame_len(src) { + Ok(len) => { + if len > self.max_frame_bytes { + return Err(RespError::too_large(self.max_frame_bytes)); + } + let frozen = src.split_to(len).freeze(); + let mut pos = 0; + Ok(monoio_codec::Decoded::Some(parse::build_value( + &frozen, &mut pos, 0, + )?)) + } + Err(RespError::Incomplete) => { + src.reserve(64); + Ok(monoio_codec::Decoded::Insufficient) + } + Err(e) => Err(e), + } + } +}