Skip to content

Commit a615abe

Browse files
committed
feat(resp-encode): support resp-encode
1 parent 5061ab0 commit a615abe

File tree

2 files changed

+185
-18
lines changed

2 files changed

+185
-18
lines changed

src/resp.rs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use std::collections::{HashMap, HashSet};
1+
use std::collections::BTreeMap;
22

33
use bytes::BytesMut;
4+
use enum_dispatch::enum_dispatch;
45

56
mod encode;
67

8+
#[enum_dispatch]
79
pub trait RespEncode {
810
fn encode(self) -> Vec<u8>;
911
}
@@ -12,6 +14,7 @@ pub trait RespDecode {
1214
fn decode(buf: Self) -> Result<RespFrame, String>;
1315
}
1416
// 之所以要定义一些新的结构体, 是因为要在实现 trait 的时候, 要区分开这些类型
17+
#[enum_dispatch(RespEncode)]
1518
pub enum RespFrame {
1619
SimpleString(SimpleString),
1720
Error(SimpleError),
@@ -32,30 +35,63 @@ pub enum RespFrame {
3235
// 2. 新类型模式:这是 Rust 中常用的一种模式,用于在类型系统层面区分不同用途的相同底层类型。比如,你可能想区分普通的字符串和特定格式的字符串。
3336
// 3. 添加方法:你可以为 SimpleString 实现方法,这些方法特定于这种类型的字符串。
3437
// 4. 语义清晰:在复杂的数据结构中(如你展示的 RespFrame 枚举),使用 SimpleString 而不是直接使用 String 可以使代码的意图更加明确。
35-
pub struct SimpleString(String);
38+
pub struct SimpleString(String); // Simple String, 用于存储简单字符串
3639
pub struct SimpleError(String);
37-
pub struct BulkString(Vec<u8>);
40+
pub struct BulkString(Vec<u8>); // 单个二进制字符串, 用于存储二进制数据(最大512MB)
3841
pub struct RespNullBulkString;
3942
pub struct RespArray(Vec<RespFrame>);
4043
pub struct RespNullArray;
4144
pub struct RespNull;
42-
pub struct RespMap(HashMap<String, RespFrame>);
43-
pub struct RespSet(HashSet<RespFrame>);
45+
#[derive(Default)]
46+
pub struct RespMap(BTreeMap<String, RespFrame>); // 改为 BTreeMap, 用于有序的 key-value 数据
47+
48+
// pub struct RespSet(HashSet<RespFrame>);
49+
pub struct RespSet(Vec<RespFrame>); // 改为 Vec, 用于有序的集合数据
4450

4551
impl SimpleString {
4652
pub fn new(s: impl Into<String>) -> Self {
4753
SimpleString(s.into())
4854
}
4955
}
5056

51-
impl RespDecode for BytesMut {
52-
fn decode(_buf: Self) -> Result<RespFrame, String> {
53-
todo!()
57+
impl SimpleError {
58+
pub fn new(s: impl Into<String>) -> Self {
59+
SimpleError(s.into())
60+
}
61+
}
62+
63+
impl BulkString {
64+
pub fn new(s: impl Into<Vec<u8>>) -> Self {
65+
BulkString(s.into())
66+
}
67+
}
68+
69+
impl RespArray {
70+
pub fn new(s: impl Into<Vec<RespFrame>>) -> Self {
71+
RespArray(s.into())
72+
}
73+
}
74+
75+
impl RespMap {
76+
pub fn new() -> Self {
77+
RespMap(BTreeMap::new())
78+
}
79+
}
80+
81+
impl RespSet {
82+
pub fn new(s: impl Into<Vec<RespFrame>>) -> Self {
83+
RespSet(s.into())
5484
}
5585
}
5686

57-
impl RespEncode for RespFrame {
58-
fn encode(self) -> Vec<u8> {
87+
impl RespDecode for BytesMut {
88+
fn decode(_buf: Self) -> Result<RespFrame, String> {
5989
todo!()
6090
}
6191
}
92+
93+
// impl RespEncode for RespFrame {
94+
// fn encode(self) -> Vec<u8> {
95+
// todo!()
96+
// }
97+
// }

src/resp/encode.rs

Lines changed: 139 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{
2-
collections::{HashMap, HashSet},
3-
ops::Deref,
2+
collections::BTreeMap,
3+
ops::{Deref, DerefMut},
44
};
55

66
use crate::{
@@ -27,7 +27,7 @@ impl RespEncode for SimpleError {
2727
// - integer: ":[<+|->]<value>\r\n"
2828
impl RespEncode for i64 {
2929
fn encode(self) -> Vec<u8> {
30-
let sign = if self < 0 { "-" } else { "+" };
30+
let sign = if self < 0 { "" } else { "+" }; // -1 => -1, 1 => +1
3131
format!(":{}{}\r\n", sign, self).into_bytes()
3232
}
3333
}
@@ -91,9 +91,16 @@ impl RespEncode for bool {
9191
// - double: ",[<+|->]<integral>[.<fractional>][<E|e>[sign]<exponent>]\r\n"
9292
impl RespEncode for f64 {
9393
fn encode(self) -> Vec<u8> {
94-
// scientific natation
95-
// format: {:+e}
96-
format!(",{:+e}\r\n", self).into_bytes()
94+
let mut buf = Vec::with_capacity(32);
95+
let ret = if self.abs() > 1e+8 || self.abs() < 1e-8 {
96+
format!(",{:+e}\r\n", self)
97+
} else {
98+
let sign = if self < 0.0 { "" } else { "+" };
99+
format!(",{}{}\r\n", sign, self)
100+
};
101+
102+
buf.extend_from_slice(&ret.into_bytes());
103+
buf
97104
}
98105
}
99106

@@ -169,17 +176,141 @@ impl Deref for RespArray {
169176
}
170177

171178
impl Deref for RespMap {
172-
type Target = HashMap<String, RespFrame>;
179+
type Target = BTreeMap<String, RespFrame>;
173180

174181
fn deref(&self) -> &Self::Target {
175182
&self.0
176183
}
177184
}
178185

186+
impl DerefMut for RespMap {
187+
fn deref_mut(&mut self) -> &mut Self::Target {
188+
&mut self.0
189+
}
190+
}
191+
179192
impl Deref for RespSet {
180-
type Target = HashSet<RespFrame>;
193+
type Target = Vec<RespFrame>;
181194

182195
fn deref(&self) -> &Self::Target {
183196
&self.0
184197
}
185198
}
199+
200+
#[cfg(test)]
201+
mod test {
202+
use super::*;
203+
204+
#[test]
205+
fn test_simple_string_encode() {
206+
let frame: RespFrame = SimpleString::new("OK".to_string()).into();
207+
assert_eq!(frame.encode(), b"+OK\r\n");
208+
}
209+
210+
#[test]
211+
fn test_error_encode() {
212+
let frame: RespFrame = SimpleError::new("Error message".to_string()).into();
213+
assert_eq!(frame.encode(), b"-Error message\r\n");
214+
}
215+
216+
#[test]
217+
fn test_integer_encode() {
218+
let frame: RespFrame = 123.into();
219+
assert_eq!(frame.encode(), b":+123\r\n");
220+
221+
// println!("{:?}", String::from_utf8_lossy(&frame.encode()));
222+
223+
let frame: RespFrame = (-123).into();
224+
assert_eq!(frame.encode(), b":-123\r\n");
225+
}
226+
227+
#[test]
228+
fn test_bulk_string_encode() {
229+
let frame: RespFrame = BulkString::new(b"hello".to_vec()).into();
230+
assert_eq!(frame.encode(), b"$5\r\nhello\r\n");
231+
}
232+
233+
#[test]
234+
fn test_null_bulk_string_encode() {
235+
let frame: RespFrame = RespNullBulkString.into();
236+
assert_eq!(frame.encode(), b"$-1\r\n");
237+
}
238+
239+
#[test]
240+
fn test_array_encode() {
241+
let frame: RespFrame = RespArray::new(vec![
242+
SimpleString::new("OK".to_string()).into(),
243+
123.into(),
244+
BulkString::new(b"hello".to_vec()).into(),
245+
])
246+
.into();
247+
assert_eq!(frame.encode(), b"*3\r\n+OK\r\n:+123\r\n$5\r\nhello\r\n");
248+
}
249+
250+
#[test]
251+
fn test_null_array_encode() {
252+
let frame: RespFrame = RespNullArray.into();
253+
assert_eq!(frame.encode(), b"*-1\r\n");
254+
}
255+
256+
#[test]
257+
fn test_null_encode() {
258+
let frame: RespFrame = RespNull.into();
259+
assert_eq!(frame.encode(), b"_\r\n");
260+
}
261+
262+
#[test]
263+
fn test_boolean_encode() {
264+
// into 和 from 是互斥的
265+
// let frame: RespFrame = true.into();
266+
let frame = RespFrame::from(true);
267+
assert_eq!(frame.encode(), b"#t\r\n");
268+
269+
let frame: RespFrame = false.into();
270+
assert_eq!(frame.encode(), b"#f\r\n");
271+
}
272+
273+
#[test]
274+
fn test_double_encode() {
275+
let frame: RespFrame = (123.456).into();
276+
assert_eq!(frame.encode(), b",+123.456\r\n");
277+
278+
let frame: RespFrame = (-123.456).into();
279+
assert_eq!(frame.encode(), b",-123.456\r\n");
280+
281+
let frame: RespFrame = 1.23456e+8.into();
282+
assert_eq!(frame.encode(), b",+1.23456e8\r\n");
283+
284+
let frame: RespFrame = (-1.23456e-9).into();
285+
assert_eq!(&frame.encode(), b",-1.23456e-9\r\n");
286+
}
287+
288+
#[test]
289+
fn test_map_encode() {
290+
let mut map = RespMap::new();
291+
map.insert(
292+
"hello".to_string(),
293+
BulkString::new("world".to_string()).into(),
294+
);
295+
map.insert("foo".to_string(), (-123456.789).into());
296+
297+
let frame: RespFrame = map.into();
298+
assert_eq!(
299+
&frame.encode(),
300+
b"%2\r\n+foo\r\n,-123456.789\r\n+hello\r\n$5\r\nworld\r\n"
301+
);
302+
}
303+
304+
#[test]
305+
fn test_set_encode() {
306+
let frame: RespFrame = RespSet::new([
307+
RespArray::new([1234.into(), true.into()]).into(),
308+
BulkString::new("world".to_string()).into(),
309+
])
310+
.into();
311+
assert_eq!(
312+
frame.encode(),
313+
b"~2\r\n*2\r\n:+1234\r\n#t\r\n$5\r\nworld\r\n"
314+
);
315+
}
316+
}

0 commit comments

Comments
 (0)