Skip to content

Commit c619348

Browse files
authored
Merge pull request #3 from upupnoah/main
feat(resp-decode): support resp decode for simple redis
2 parents 6e996c8 + 58d29a6 commit c619348

File tree

7 files changed

+625
-13
lines changed

7 files changed

+625
-13
lines changed

Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ authors = ["Noah <[email protected]>"]
1010
anyhow = "^1.0"
1111
bytes = "^1.6.1"
1212
enum_dispatch = "^0.3.13"
13+
thiserror = "^1.0.62"

examples/bytes_mut.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use anyhow::Result;
2+
use bytes::BytesMut;
3+
fn main() -> Result<()> {
4+
let a = "hello"; // a.as_bytes() = b"hello"
5+
6+
// bytes_mut
7+
let mut bytes_mut = BytesMut::new();
8+
bytes_mut.extend_from_slice(a.as_bytes());
9+
println!("bytes_mut: {:?}", bytes_mut);
10+
11+
let b = bytes_mut.split_to(3);
12+
println!("b: {:?}", b);
13+
println!("after split_to(3) -> bytes_mut: {:?}", bytes_mut);
14+
Ok(())
15+
}

examples/enum_dispatch.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use enum_dispatch::enum_dispatch;
2+
3+
#[enum_dispatch]
4+
trait DoSomething {
5+
fn do_something(&self);
6+
}
7+
8+
#[enum_dispatch(DoSomething)]
9+
enum Types {
10+
Apple(A),
11+
Banana(B),
12+
}
13+
14+
struct A;
15+
struct B;
16+
17+
impl DoSomething for A {
18+
fn do_something(&self) {
19+
println!("A");
20+
}
21+
}
22+
23+
impl DoSomething for B {
24+
fn do_something(&self) {
25+
println!("B");
26+
}
27+
}
28+
fn main() {
29+
// test enum_dispatch
30+
let apple = Types::Apple(A);
31+
let banana = Types::Banana(B);
32+
33+
let type_apple = apple;
34+
let type_banana = banana;
35+
36+
// 都是 types 类型的, 但是结果不同, enum_dispatch 相当于是主动帮我 match 了
37+
type_apple.do_something();
38+
type_banana.do_something();
39+
}

examples/thiserorr_anyhow.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use anyhow::{Context, Result};
2+
use std::io::Error as IoError;
3+
use std::num::ParseIntError;
4+
use thiserror::Error;
5+
6+
// 定义自定义错误类型
7+
#[derive(Error, Debug)]
8+
enum MyError {
9+
#[error("An IO error occurred: {0}")]
10+
Io(#[from] IoError),
11+
12+
#[error("A parsing error occurred: {0}")]
13+
Parse(#[from] ParseIntError),
14+
15+
#[error("Custom error: {0}")]
16+
Custom(String),
17+
18+
#[error("Anyhow error: {0}")]
19+
Anyhow(#[from] anyhow::Error),
20+
}
21+
22+
// 一个可能返回错误的函数
23+
fn parse_number(input: &str) -> Result<i32, MyError> {
24+
let trimmed = input.trim();
25+
if trimmed.is_empty() {
26+
return Err(MyError::Custom("Input is empty".into()));
27+
}
28+
29+
let number: i32 = trimmed
30+
.parse()
31+
// .map_err(|e| MyError::Parse(e))
32+
.map_err(MyError::Parse) // 更好的写法
33+
.context("Failed to parse number")?;
34+
Ok(number)
35+
}
36+
37+
fn main() -> Result<(), MyError> {
38+
// 示例一: 正确的输入
39+
match parse_number("42") {
40+
Ok(number) => println!("Parsed number: {}", number),
41+
Err(e) => eprintln!("Error: {}", e),
42+
}
43+
44+
// 示例二: 空输入
45+
match parse_number("") {
46+
Ok(number) => println!("Parsed number: {}", number),
47+
Err(e) => eprintln!("Error: {}", e),
48+
}
49+
50+
// 示例三: 无效输入
51+
match parse_number("abc") {
52+
Ok(number) => println!("Parsed number: {}", number),
53+
Err(e) => eprintln!("Error: {}", e),
54+
}
55+
56+
Ok(())
57+
}

src/resp.rs

Lines changed: 139 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,60 @@
1-
use std::collections::BTreeMap;
2-
3-
use bytes::BytesMut;
1+
use bytes::{Buf, BytesMut};
42
use enum_dispatch::enum_dispatch;
3+
use std::collections::BTreeMap;
4+
use thiserror::Error;
55

6+
mod decode;
67
mod encode;
78

9+
const CRLF: &[u8] = b"\r\n";
10+
const CRLF_LEN: usize = CRLF.len();
11+
812
#[enum_dispatch]
913
pub trait RespEncode {
1014
fn encode(self) -> Vec<u8>;
1115
}
1216

13-
pub trait RespDecode {
14-
fn decode(buf: Self) -> Result<RespFrame, String>;
17+
// Sized 表示这个 trait 只能被 [大小确定的类型] 实现
18+
// 因为 decode 方法的返回值是一个 Self, 因此必须将这个 trait 标记为 Sized
19+
pub trait RespDecode: Sized {
20+
const PREFIX: &'static str;
21+
fn decode(buf: &mut BytesMut) -> Result<Self, RespError>;
22+
fn expect_length(buf: &[u8]) -> Result<usize, RespError>;
23+
}
24+
25+
#[derive(Error, Debug, PartialEq, Eq)]
26+
pub enum RespError {
27+
// region: --- thiserror format usage
28+
29+
// #[error("{var}")] ⟶ write!("{}", self.var)
30+
// #[error("{0}")] ⟶ write!("{}", self.0)
31+
// #[error("{var:?}")] ⟶ write!("{:?}", self.var)
32+
// #[error("{0:?}")] ⟶ write!("{:?}", self.0)
33+
34+
// endregion: --- thiserror format usage
35+
#[error("Invalid frame: {0}")] // 这里的 0 表示 self.0。 会转化为 write!
36+
InvalidFrame(String),
37+
#[error("Invalid frame type: {0}")]
38+
InvalidFrameType(String),
39+
#[error("Invalid frame length: {0}")]
40+
InvalidFrameLength(isize),
41+
#[error("Frame is not complete")]
42+
NotComplete,
43+
44+
#[error("Parse error: {0}")]
45+
ParseIntError(#[from] std::num::ParseIntError),
46+
#[error("Utf8 error: {0}")]
47+
Utf8Error(#[from] std::string::FromUtf8Error),
48+
#[error("Parse float error: {0}")]
49+
ParseFloatError(#[from] std::num::ParseFloatError),
1550
}
51+
52+
// pub trait RespDecode: Sized {
53+
// const PREFIX: &'static str;
54+
// fn decode(buf: &mut BytesMut) -> Result<Self, RespError>;
55+
// fn expect_length(buf: &[u8]) -> Result<usize, RespError>;
56+
// }
57+
1658
// 之所以要定义一些新的结构体, 是因为要在实现 trait 的时候, 要区分开这些类型
1759
#[enum_dispatch(RespEncode)]
1860
pub enum RespFrame {
@@ -35,12 +77,19 @@ pub enum RespFrame {
3577
// 2. 新类型模式:这是 Rust 中常用的一种模式,用于在类型系统层面区分不同用途的相同底层类型。比如,你可能想区分普通的字符串和特定格式的字符串。
3678
// 3. 添加方法:你可以为 SimpleString 实现方法,这些方法特定于这种类型的字符串。
3779
// 4. 语义清晰:在复杂的数据结构中(如你展示的 RespFrame 枚举),使用 SimpleString 而不是直接使用 String 可以使代码的意图更加明确。
80+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
3881
pub struct SimpleString(String); // Simple String, 用于存储简单字符串
82+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
3983
pub struct SimpleError(String);
84+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
4085
pub struct BulkString(Vec<u8>); // 单个二进制字符串, 用于存储二进制数据(最大512MB)
86+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
4187
pub struct RespNullBulkString;
88+
4289
pub struct RespArray(Vec<RespFrame>);
90+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
4391
pub struct RespNullArray;
92+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
4493
pub struct RespNull;
4594
#[derive(Default)]
4695
pub struct RespMap(BTreeMap<String, RespFrame>); // 改为 BTreeMap, 用于有序的 key-value 数据
@@ -84,14 +133,91 @@ impl RespSet {
84133
}
85134
}
86135

87-
impl RespDecode for BytesMut {
88-
fn decode(_buf: Self) -> Result<RespFrame, String> {
89-
todo!()
136+
// utility functions
137+
fn extract_fixed_data(
138+
buf: &mut BytesMut,
139+
expect: &str,
140+
expect_type: &str,
141+
) -> Result<(), RespError> {
142+
if buf.len() < expect.len() {
143+
return Err(RespError::NotComplete);
90144
}
145+
146+
if !buf.starts_with(expect.as_bytes()) {
147+
return Err(RespError::InvalidFrameType(format!(
148+
"expect: {}, got: {:?}",
149+
expect_type, buf
150+
)));
151+
}
152+
153+
buf.advance(expect.len());
154+
Ok(())
91155
}
92156

93-
// impl RespEncode for RespFrame {
94-
// fn encode(self) -> Vec<u8> {
95-
// todo!()
96-
// }
97-
// }
157+
fn extract_simple_frame_data(buf: &[u8], prefix: &str) -> Result<usize, RespError> {
158+
if buf.len() < 3 {
159+
return Err(RespError::NotComplete);
160+
}
161+
162+
if !buf.starts_with(prefix.as_bytes()) {
163+
return Err(RespError::InvalidFrameType(format!(
164+
"expect: SimpleString({}), got: {:?}",
165+
prefix, buf
166+
)));
167+
}
168+
169+
let end = find_crlf(buf, 1).ok_or(RespError::NotComplete)?;
170+
171+
Ok(end)
172+
}
173+
174+
// find nth CRLF in the buffer
175+
fn find_crlf(buf: &[u8], nth: usize) -> Option<usize> {
176+
let mut count = 0;
177+
for i in 1..buf.len() - 1 {
178+
if buf[i] == b'\r' && buf[i + 1] == b'\n' {
179+
count += 1;
180+
if count == nth {
181+
return Some(i);
182+
}
183+
}
184+
}
185+
None
186+
}
187+
188+
fn parse_length(buf: &[u8], prefix: &str) -> Result<(usize, usize), RespError> {
189+
let end = extract_simple_frame_data(buf, prefix)?;
190+
let s = String::from_utf8_lossy(&buf[prefix.len()..end]);
191+
Ok((end, s.parse()?))
192+
}
193+
194+
fn calc_total_length(buf: &[u8], end: usize, len: usize, prefix: &str) -> Result<usize, RespError> {
195+
let mut total = end + CRLF_LEN;
196+
let mut data = &buf[total..];
197+
match prefix {
198+
"*" | "~" => {
199+
// find nth CRLF in the buffer, for array and set, we need to find 1 CRLF for each element
200+
for _ in 0..len {
201+
let len = RespFrame::expect_length(data)?;
202+
data = &data[len..];
203+
total += len;
204+
}
205+
Ok(total)
206+
}
207+
"%" => {
208+
// find nth CRLF in the buffer. For map, we need to find 2 CRLF for each key-value pair
209+
for _ in 0..len {
210+
let len = SimpleString::expect_length(data)?;
211+
212+
data = &data[len..];
213+
total += len;
214+
215+
let len = RespFrame::expect_length(data)?;
216+
data = &data[len..];
217+
total += len;
218+
}
219+
Ok(total)
220+
}
221+
_ => Ok(len + CRLF_LEN),
222+
}
223+
}

0 commit comments

Comments
 (0)