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

Download history 61138/week @ 2024-04-22 46796/week @ 2024-04-29 55043/week @ 2024-05-06 51262/week @ 2024-05-13 50249/week @ 2024-05-20 41048/week @ 2024-05-27 41407/week @ 2024-06-03 44017/week @ 2024-06-10 45975/week @ 2024-06-17 50774/week @ 2024-06-24 36606/week @ 2024-07-01 48509/week @ 2024-07-08 46397/week @ 2024-07-15 44757/week @ 2024-07-22 39432/week @ 2024-07-29 38111/week @ 2024-08-05

169,651 每月下载量
27 crate 中使用 (3 个直接使用)

MIT 许可证

480KB
13K SLoC

Redis 协议

License License CircleCI Crates.io API docs

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 启用 FromResp2FromResp3 特性行为接口。
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