13 个版本 (稳定)
5.0.1 | 2024年4月5日 |
---|---|
5.0.0 | 2024年3月31日 |
4.1.0 | 2022年6月12日 |
4.0.1 | 2022年1月19日 |
0.1.1 | 2018年10月4日 |
#1 在 #resp
169,651 每月下载量
在 27 个 crate 中使用 (3 个直接使用)
480KB
13K SLoC
Redis 协议
Rust 对 Redis 协议的实现。
特性
- 基于 Bytes 的所有权和零拷贝解析接口。
- 支持 RESP2 和 RESP3 帧结构,包括流式帧。
- 发布-订阅消息工具。
- 集群 哈希槽 接口。
- RESP2 和 RESP3 编解码器 接口。
- 从 RESP2 转换到 RESP3 的实用函数。
- 将帧转换为其他类型的特性行为。
示例
use redis_protocol::resp2::{
decode::decode,
encode::encode,
types::{OwnedFrame as Frame, Resp2Frame}
};
fn main() {
let frame = Frame::BulkString("foobar".into());
let mut buf = vec![0; frame.encode_len()];
let len = encode(&mut buf, &frame).expect("Error encoding frame");
println!("Encoded {} bytes into buffer with contents {:?}", len, buf);
// ["Foo", nil, "Bar"]
let buf: &[u8] = b"*3\r\n$3\r\nFoo\r\n$-1\r\n$3\r\nBar\r\n";
match decode(&buf).unwrap() {
Some((frame, amt)) => println!("Parsed {:?} and read {} bytes", frame, amt),
None => println!("Incomplete frame."),
};
}
构建特性
名称 | 默认 | 描述 |
---|---|---|
std |
x | 启用 stdlib 特性和大多数依赖项默认特性。 |
resp2 |
x | 启用 RESP2 接口。 |
resp3 |
x | 启用 RESP3 接口。 |
bytes |
通过 Bytes 类型启用零拷贝解析接口。 | |
decode-logs |
在帧解码过程中启用额外的调试 TRACE 日志。 | |
codec |
启用 RESP2 和 RESP3 Tokio 编解码器 接口。 | |
convert |
启用 FromResp2 和 FromResp3 特性行为接口。 |
|
index-map |
使用 IndexMap 类型代替 HashMap 。这对于测试很有用,也可能对调用者有用。 |
no_std
no_std
构建:通过禁用 std
特性支持。但是,一些可选依赖项必须作为替代方案激活。
redis-protocol = { version = "X.X.X", default-features = false, features = ["libm", "hashbrown", "alloc"] }
解码
RESP2 和 RESP3 接口都支持 3 种不同的 Frame
接口。这些接口旨在支持不同的用例
OwnedFrame
类型使用core
容器类型来实现所有权的帧变体。这是最简单的帧接口,但在解码时通常需要移动或复制底层缓冲区内容。BytesFrame
类型使用 Bytes 作为底层容器。启用bytes
功能标志将启用此帧类型以及一系列关联函数,这些函数避免了移动或复制BytesMut
的内容。RangeFrame
类型表示与关联缓冲区中的范围,通常用于实现零拷贝解析的形式。这是最低级别的接口。
RESP2 OwnedFrame
解码示例
从测试中改编的简单数组解码示例
use redis_protocol::resp2::{
decode::decode,
types::{OwnedFrame, Resp2Frame}
};
fn should_decode_array() {
// ["Foo", nil, "Bar"]
let buf: &[u8] = b"*3\r\n$3\r\nFoo\r\n$-1\r\n$3\r\nBar\r\n";
let (frame, amt) = decode(&buf).unwrap().unwrap();
assert_eq!(frame, OwnedFrame::Array(vec![
OwnedFrame::BulkString("Foo".into()),
OwnedFrame::Null,
OwnedFrame::BulkString("Bar".into())
]));
assert_eq!(amt, buf.len());
}
RESP2 BytesFrame
解码示例
从测试中改编的数组解码示例
use redis_protocol::resp2::{
decode::decode_bytes_mut,
types::{BytesFrame, Resp2Frame}
};
use bytes::BytesMut;
fn should_decode_array_no_nulls() {
let expected = (
BytesFrame::Array(vec![
BytesFrame::SimpleString("Foo".into()),
BytesFrame::SimpleString("Bar".into()),
]),
16,
);
let mut bytes: BytesMut = "*2\r\n+Foo\r\n+Bar\r\n".into();
let total_len = bytes.len();
let (frame, amt, buf) = match decode_bytes_mut(&mut bytes) {
Ok(Some(result)) => result,
Ok(None) => panic!("Expected complete frame"),
Err(e) => panic!("{:?}", e)
};
assert_eq!(frame, expected.0, "decoded frame matched");
assert_eq!(amt, expected.1, "decoded frame len matched");
assert_eq!(buf.len(), expected.1, "output buffer len matched");
assert_eq!(buf.len() + bytes.len(), total_len, "total len matched");
}
RESP2 RangeFrame
解码示例
实现一个自定义的可借用帧类型,该类型只能表示 BulkString 和 SimpleString
use redis_protocol::resp2::{
decode::decode_range,
types::RangeFrame
};
use std::str;
enum MyBorrowedFrame<'a> {
BulkString(&'a [u8]),
SimpleString(&'a str),
}
fn decode_borrowed(buf: &[u8]) -> Option<MyBorrowedFrame> {
match decode_range(buf).ok()? {
Some((RangeFrame::BulkString((i, j)), _)) => {
Some(MyBorrowedFrame::BulkString(&buf[i..j]))
}
Some((RangeFrame::SimpleString((i, j)), _)) => {
let parsed = str::from_utf8(&buf[i..j]).ok()?;
Some(MyBorrowedFrame::SimpleString(parsed))
}
_ => None,
}
}
依赖项
~1-3MB
~54K SLoC