1pub fn encode_map_header(out: &mut Vec<u8>, count: i64) {
25 out.push(b'%');
26 push_int(out, count);
27 out.extend_from_slice(b"\r\n");
28}
29
30pub fn encode_set_header(out: &mut Vec<u8>, count: i64) {
36 out.push(b'~');
37 push_int(out, count);
38 out.extend_from_slice(b"\r\n");
39}
40
41pub fn encode_push_header(out: &mut Vec<u8>, count: i64) {
46 out.push(b'>');
47 push_int(out, count);
48 out.extend_from_slice(b"\r\n");
49}
50
51pub fn encode_double(out: &mut Vec<u8>, v: f64) {
60 out.push(b',');
61 if v.is_nan() {
62 out.extend_from_slice(b"nan");
63 } else if v.is_infinite() {
64 out.extend_from_slice(if v > 0.0 { b"inf" } else { b"-inf" });
65 } else {
66 if v == v.trunc() && v.abs() < 1e17 {
70 push_int(out, v as i64);
71 } else {
72 use std::io::Write as _;
76 let _ = write!(out, "{v}");
77 }
78 }
79 out.extend_from_slice(b"\r\n");
80}
81
82pub fn encode_boolean(out: &mut Vec<u8>, v: bool) {
84 out.extend_from_slice(if v { b"#t\r\n" } else { b"#f\r\n" });
85}
86
87pub fn encode_null(out: &mut Vec<u8>) {
90 out.extend_from_slice(b"_\r\n");
91}
92
93pub fn encode_big_number(out: &mut Vec<u8>, digits: &[u8]) {
97 out.reserve(digits.len() + 4);
98 out.push(b'(');
99 out.extend_from_slice(digits);
100 out.extend_from_slice(b"\r\n");
101}
102
103pub fn encode_verbatim(out: &mut Vec<u8>, fmt: [u8; 3], data: &[u8]) {
112 let total_len = 4 + data.len();
113 out.reserve(total_len + 16);
114 out.push(b'=');
115 push_int(out, total_len as i64);
116 out.extend_from_slice(b"\r\n");
117 out.extend_from_slice(&fmt);
118 out.push(b':');
119 out.extend_from_slice(data);
120 out.extend_from_slice(b"\r\n");
121}
122
123pub fn encode_blob_error(out: &mut Vec<u8>, msg: &[u8]) {
126 out.reserve(msg.len() + 16);
127 out.push(b'!');
128 push_int(out, msg.len() as i64);
129 out.extend_from_slice(b"\r\n");
130 out.extend_from_slice(msg);
131 out.extend_from_slice(b"\r\n");
132}
133
134fn push_int(out: &mut Vec<u8>, n: i64) {
138 if n == 0 {
139 out.push(b'0');
140 return;
141 }
142 let mut tmp = [0u8; 20];
143 let mut i = tmp.len();
144 let neg = n < 0;
145 let mut v = n;
146 while v != 0 {
147 let digit = (v % 10).unsigned_abs() as u8;
148 i -= 1;
149 tmp[i] = b'0' + digit;
150 v /= 10;
151 }
152 if neg {
153 out.push(b'-');
154 }
155 out.extend_from_slice(&tmp[i..]);
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use crate::{parse_reply, Reply};
162
163 #[test]
166 fn map_header_round_trip() {
167 let mut out = Vec::new();
168 encode_map_header(&mut out, 2);
169 crate::encode_integer(&mut out, 1);
171 crate::encode_bulk(&mut out, b"a");
172 crate::encode_integer(&mut out, 2);
173 crate::encode_bulk(&mut out, b"b");
174 assert_eq!(out, b"%2\r\n:1\r\n$1\r\na\r\n:2\r\n$1\r\nb\r\n");
175 let (r, used) = parse_reply(&out).unwrap().unwrap();
176 assert_eq!(used, out.len());
177 assert_eq!(
178 r,
179 Reply::Map(vec![
180 (Reply::Int(1), Reply::Bulk(b"a".to_vec())),
181 (Reply::Int(2), Reply::Bulk(b"b".to_vec())),
182 ])
183 );
184 }
185
186 #[test]
187 fn set_header_round_trip() {
188 let mut out = Vec::new();
189 encode_set_header(&mut out, 3);
190 for i in 1..=3 {
191 crate::encode_integer(&mut out, i);
192 }
193 assert_eq!(out, b"~3\r\n:1\r\n:2\r\n:3\r\n");
194 let (r, _) = parse_reply(&out).unwrap().unwrap();
195 assert_eq!(r, Reply::Set(vec![Reply::Int(1), Reply::Int(2), Reply::Int(3)]));
196 }
197
198 #[test]
199 fn push_header_round_trip() {
200 let mut out = Vec::new();
201 encode_push_header(&mut out, 3);
202 crate::encode_simple_string(&mut out, "message");
203 crate::encode_bulk(&mut out, b"news");
204 crate::encode_bulk(&mut out, b"hello");
205 assert_eq!(out, b">3\r\n+message\r\n$4\r\nnews\r\n$5\r\nhello\r\n");
206 let (r, _) = parse_reply(&out).unwrap().unwrap();
207 assert_eq!(
208 r,
209 Reply::Push(vec![
210 Reply::Simple(b"message".to_vec()),
211 Reply::Bulk(b"news".to_vec()),
212 Reply::Bulk(b"hello".to_vec()),
213 ])
214 );
215 }
216
217 #[test]
218 fn double_round_trip() {
219 let mut out = Vec::new();
220 encode_double(&mut out, 1.5);
222 assert_eq!(out, b",1.5\r\n");
223 let (r, _) = parse_reply(&out).unwrap().unwrap();
224 assert_eq!(r, Reply::Double(1.5));
225
226 out.clear();
227 encode_double(&mut out, 5.0); assert_eq!(out, b",5\r\n");
229 let (r, _) = parse_reply(&out).unwrap().unwrap();
230 assert_eq!(r, Reply::Double(5.0));
231
232 out.clear();
233 encode_double(&mut out, f64::INFINITY);
234 assert_eq!(out, b",inf\r\n");
235
236 out.clear();
237 encode_double(&mut out, f64::NEG_INFINITY);
238 assert_eq!(out, b",-inf\r\n");
239
240 out.clear();
241 encode_double(&mut out, f64::NAN);
242 assert_eq!(out, b",nan\r\n");
243 }
244
245 #[test]
246 fn boolean_and_null_round_trip() {
247 let mut out = Vec::new();
248 encode_boolean(&mut out, true);
249 assert_eq!(out, b"#t\r\n");
250 let (r, _) = parse_reply(&out).unwrap().unwrap();
251 assert_eq!(r, Reply::Boolean(true));
252
253 out.clear();
254 encode_boolean(&mut out, false);
255 assert_eq!(out, b"#f\r\n");
256 let (r, _) = parse_reply(&out).unwrap().unwrap();
257 assert_eq!(r, Reply::Boolean(false));
258
259 out.clear();
260 encode_null(&mut out);
261 assert_eq!(out, b"_\r\n");
262 let (r, _) = parse_reply(&out).unwrap().unwrap();
263 assert_eq!(r, Reply::Null);
264 }
265
266 #[test]
267 fn verbatim_round_trip() {
268 let mut out = Vec::new();
269 encode_verbatim(&mut out, *b"txt", b"Some string");
270 assert_eq!(out, b"=15\r\ntxt:Some string\r\n");
271 let (r, _) = parse_reply(&out).unwrap().unwrap();
272 assert_eq!(r, Reply::Verbatim { fmt: *b"txt", data: b"Some string".to_vec() });
273 }
274
275 #[test]
276 fn big_number_round_trip() {
277 let mut out = Vec::new();
278 encode_big_number(&mut out, b"170141183460469231731687303715884105727");
279 assert_eq!(out, b"(170141183460469231731687303715884105727\r\n");
280 let (r, _) = parse_reply(&out).unwrap().unwrap();
281 assert_eq!(
282 r,
283 Reply::BigNumber(b"170141183460469231731687303715884105727".to_vec())
284 );
285 }
286
287 #[test]
288 fn blob_error_round_trip() {
289 let mut out = Vec::new();
290 encode_blob_error(&mut out, b"ERR bad thing\nwith newline");
291 let (r, _) = parse_reply(&out).unwrap().unwrap();
292 assert_eq!(r, Reply::BlobError(b"ERR bad thing\nwith newline".to_vec()));
293 }
294}