@@ -55,7 +55,45 @@ async fn main() -> Result<()> {
5555 Ok(())
5656}
5757```
58+ ## Byte arguments and serde limitations
5859
60+ Due to how serde handles byte types, passing raw byte values like `&[u8]`,
61+ `Vec<u8>`, or byte literals like `b"val"` directly as command arguments
62+ will **not** produce a single RESP bulk string. Instead, serde serializes
63+ them as sequences of individual integer values, resulting in a runtime error.
64+
65+ This is a fundamental serde limitation: without specialization, there is no
66+ way to distinguish a `&[u8]` from any other `&[T]` at the trait level.
67+ Note that `&str` works correctly because it is a distinct type, not a slice.
68+
69+ To pass raw bytes as a single bulk string argument, use the provided adapter types:
70+
71+ - [`BulkString`] for owned byte data (`Vec<u8>`) — moves ownership, zero allocation
72+ - [`RefBulkString`] for borrowed byte data (`&[u8]`) — zero allocation
73+
74+ #### Example
75+ ```
76+ use rustis::{
77+ client::Client,
78+ commands::StringCommands,
79+ resp::{BulkString, RefBulkString},
80+ Result,
81+ };
82+
83+ #[cfg_attr(feature = "tokio-runtime", tokio::main)]
84+ #[cfg_attr(feature = "async-std-runtime", async_std::main)]
85+ async fn main() -> Result<()> {
86+ let client = Client::connect("127.0.0.1:6379").await?;
87+
88+ // &[u8]: use RefBulkString (zero allocation, borrowed)
89+ client.set("key", RefBulkString::new(b"val")).await?;
90+
91+ // Vec<u8>: use BulkString (zero allocation, owned)
92+ client.set("key", BulkString::new(b"val".to_vec())).await?;
93+
94+ Ok(())
95+ }
96+ ```
5997# Command results
6098
6199**rustis** provides an idiomatic way to convert command results into Rust types with the help of [serde](serde.rs)
0 commit comments