1pub const MAX_PACKSTREAM_DEPTH: usize = 32;
30
31pub const MAX_MESSAGE_BYTES: usize = 1024 * 1024;
35
36pub const MAX_CHUNK_BYTES: usize = u16::MAX as usize;
38
39#[derive(Debug, Clone, PartialEq)]
44pub enum Value {
45 Null,
46 Bool(bool),
47 Int(i64),
48 Float(f64),
49 Bytes(Vec<u8>),
50 String(String),
51 List(Vec<Value>),
52 Map(Vec<(String, Value)>),
53 Struct { tag: u8, fields: Vec<Value> },
54}
55
56impl Value {
57 pub fn get(&self, key: &str) -> Option<&Value> {
59 match self {
60 Value::Map(entries) => entries.iter().rev().find(|(k, _)| k == key).map(|(_, v)| v),
61 _ => None,
62 }
63 }
64
65 pub fn as_str(&self) -> Option<&str> {
66 match self {
67 Value::String(s) => Some(s),
68 _ => None,
69 }
70 }
71
72 pub fn as_int(&self) -> Option<i64> {
73 match self {
74 Value::Int(i) => Some(*i),
75 _ => None,
76 }
77 }
78
79 pub fn map<K: Into<String>>(entries: impl IntoIterator<Item = (K, Value)>) -> Value {
81 Value::Map(entries.into_iter().map(|(k, v)| (k.into(), v)).collect())
82 }
83
84 pub fn string(s: impl Into<String>) -> Value {
85 Value::String(s.into())
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq)]
91pub enum DecodeError {
92 UnexpectedEnd,
94 TooDeep,
96 ReservedMarker(u8),
98 NonStringKey,
100 InvalidUtf8,
102 DeclaredLengthExceedsInput { declared: u64, remaining: usize },
104 TrailingBytes(usize),
106}
107
108impl std::fmt::Display for DecodeError {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 match self {
111 DecodeError::UnexpectedEnd => write!(f, "input ended inside a value"),
112 DecodeError::TooDeep => {
113 write!(f, "nesting deeper than {MAX_PACKSTREAM_DEPTH} levels")
114 }
115 DecodeError::ReservedMarker(m) => write!(f, "reserved marker byte 0x{m:02X}"),
116 DecodeError::NonStringKey => write!(f, "map key is not a string"),
117 DecodeError::InvalidUtf8 => write!(f, "string is not UTF-8"),
118 DecodeError::DeclaredLengthExceedsInput {
119 declared,
120 remaining,
121 } => write!(
122 f,
123 "declared length {declared} exceeds the {remaining} bytes remaining"
124 ),
125 DecodeError::TrailingBytes(n) => write!(f, "{n} bytes after the value"),
126 }
127 }
128}
129
130impl std::error::Error for DecodeError {}
131
132pub fn decode(bytes: &[u8]) -> Result<Value, DecodeError> {
134 let mut pos = 0;
135 let value = decode_at(bytes, &mut pos, 1)?;
136 if pos != bytes.len() {
137 return Err(DecodeError::TrailingBytes(bytes.len() - pos));
138 }
139 Ok(value)
140}
141
142fn take<'a>(bytes: &'a [u8], pos: &mut usize, n: usize) -> Result<&'a [u8], DecodeError> {
143 let end = pos.checked_add(n).ok_or(DecodeError::UnexpectedEnd)?;
144 if end > bytes.len() {
145 return Err(DecodeError::UnexpectedEnd);
146 }
147 let slice = &bytes[*pos..end];
148 *pos = end;
149 Ok(slice)
150}
151
152fn read_uint(bytes: &[u8], pos: &mut usize, width: usize) -> Result<u64, DecodeError> {
153 let raw = take(bytes, pos, width)?;
154 Ok(raw.iter().fold(0u64, |acc, b| (acc << 8) | u64::from(*b)))
155}
156
157fn check_declared(
159 bytes: &[u8],
160 pos: usize,
161 count: u64,
162 min_bytes_each: u64,
163) -> Result<usize, DecodeError> {
164 let remaining = bytes.len() - pos;
165 let needed = count.saturating_mul(min_bytes_each);
166 if needed > remaining as u64 {
167 return Err(DecodeError::DeclaredLengthExceedsInput {
168 declared: count,
169 remaining,
170 });
171 }
172 Ok(count as usize)
174}
175
176fn decode_at(bytes: &[u8], pos: &mut usize, depth: usize) -> Result<Value, DecodeError> {
177 let marker = take(bytes, pos, 1)?[0];
178 match marker {
179 0x00..=0x7F => Ok(Value::Int(i64::from(marker))),
181 0xF0..=0xFF => Ok(Value::Int(i64::from(marker as i8))),
182 0x80..=0x8F => decode_string(bytes, pos, u64::from(marker & 0x0F)),
183 0x90..=0x9F => decode_list(bytes, pos, u64::from(marker & 0x0F), depth),
184 0xA0..=0xAF => decode_map(bytes, pos, u64::from(marker & 0x0F), depth),
185 0xB0..=0xBF => decode_struct(bytes, pos, u64::from(marker & 0x0F), depth),
186 0xC0 => Ok(Value::Null),
187 0xC1 => {
188 let raw = take(bytes, pos, 8)?;
189 let mut buf = [0u8; 8];
190 buf.copy_from_slice(raw);
191 Ok(Value::Float(f64::from_be_bytes(buf)))
192 }
193 0xC2 => Ok(Value::Bool(false)),
194 0xC3 => Ok(Value::Bool(true)),
195 0xC8 => Ok(Value::Int(i64::from(take(bytes, pos, 1)?[0] as i8))),
196 0xC9 => {
197 let raw = take(bytes, pos, 2)?;
198 Ok(Value::Int(i64::from(i16::from_be_bytes([raw[0], raw[1]]))))
199 }
200 0xCA => {
201 let raw = take(bytes, pos, 4)?;
202 Ok(Value::Int(i64::from(i32::from_be_bytes([
203 raw[0], raw[1], raw[2], raw[3],
204 ]))))
205 }
206 0xCB => {
207 let raw = take(bytes, pos, 8)?;
208 let mut buf = [0u8; 8];
209 buf.copy_from_slice(raw);
210 Ok(Value::Int(i64::from_be_bytes(buf)))
211 }
212 0xCC..=0xCE => {
213 let width = 1usize << (marker - 0xCC);
214 let len = read_uint(bytes, pos, width)?;
215 let len = check_declared(bytes, *pos, len, 1)?;
216 Ok(Value::Bytes(take(bytes, pos, len)?.to_vec()))
217 }
218 0xD0..=0xD2 => {
219 let width = 1usize << (marker - 0xD0);
220 let len = read_uint(bytes, pos, width)?;
221 decode_string(bytes, pos, len)
222 }
223 0xD4..=0xD6 => {
224 let width = 1usize << (marker - 0xD4);
225 let count = read_uint(bytes, pos, width)?;
226 decode_list(bytes, pos, count, depth)
227 }
228 0xD8..=0xDA => {
229 let width = 1usize << (marker - 0xD8);
230 let count = read_uint(bytes, pos, width)?;
231 decode_map(bytes, pos, count, depth)
232 }
233 0xDC => {
236 let count = read_uint(bytes, pos, 1)?;
237 decode_struct(bytes, pos, count, depth)
238 }
239 0xDD => {
240 let count = read_uint(bytes, pos, 2)?;
241 decode_struct(bytes, pos, count, depth)
242 }
243 other => Err(DecodeError::ReservedMarker(other)),
244 }
245}
246
247fn decode_string(bytes: &[u8], pos: &mut usize, len: u64) -> Result<Value, DecodeError> {
248 let len = check_declared(bytes, *pos, len, 1)?;
249 let raw = take(bytes, pos, len)?;
250 std::str::from_utf8(raw)
251 .map(|s| Value::String(s.to_string()))
252 .map_err(|_| DecodeError::InvalidUtf8)
253}
254
255fn decode_list(
256 bytes: &[u8],
257 pos: &mut usize,
258 count: u64,
259 depth: usize,
260) -> Result<Value, DecodeError> {
261 if depth > MAX_PACKSTREAM_DEPTH {
262 return Err(DecodeError::TooDeep);
263 }
264 let count = check_declared(bytes, *pos, count, 1)?;
265 let mut items = Vec::with_capacity(count);
266 for _ in 0..count {
267 items.push(decode_at(bytes, pos, depth + 1)?);
268 }
269 Ok(Value::List(items))
270}
271
272fn decode_map(
273 bytes: &[u8],
274 pos: &mut usize,
275 count: u64,
276 depth: usize,
277) -> Result<Value, DecodeError> {
278 if depth > MAX_PACKSTREAM_DEPTH {
279 return Err(DecodeError::TooDeep);
280 }
281 let count = check_declared(bytes, *pos, count, 2)?;
282 let mut entries = Vec::with_capacity(count);
283 for _ in 0..count {
284 let key = match decode_at(bytes, pos, depth + 1)? {
285 Value::String(s) => s,
286 _ => return Err(DecodeError::NonStringKey),
287 };
288 let value = decode_at(bytes, pos, depth + 1)?;
289 entries.push((key, value));
290 }
291 Ok(Value::Map(entries))
292}
293
294fn decode_struct(
295 bytes: &[u8],
296 pos: &mut usize,
297 count: u64,
298 depth: usize,
299) -> Result<Value, DecodeError> {
300 if depth > MAX_PACKSTREAM_DEPTH {
301 return Err(DecodeError::TooDeep);
302 }
303 let tag = take(bytes, pos, 1)?[0];
304 let count = check_declared(bytes, *pos, count, 1)?;
305 let mut fields = Vec::with_capacity(count);
306 for _ in 0..count {
307 fields.push(decode_at(bytes, pos, depth + 1)?);
308 }
309 Ok(Value::Struct { tag, fields })
310}
311
312pub fn encode(value: &Value, out: &mut Vec<u8>) {
314 match value {
315 Value::Null => out.push(0xC0),
316 Value::Bool(false) => out.push(0xC2),
317 Value::Bool(true) => out.push(0xC3),
318 Value::Int(i) => encode_int(*i, out),
319 Value::Float(f) => {
320 out.push(0xC1);
321 out.extend_from_slice(&f.to_be_bytes());
322 }
323 Value::Bytes(b) => {
324 encode_size(b.len(), [0xCC, 0xCD, 0xCE], None, out);
325 out.extend_from_slice(b);
326 }
327 Value::String(s) => {
328 encode_size(s.len(), [0xD0, 0xD1, 0xD2], Some(0x80), out);
329 out.extend_from_slice(s.as_bytes());
330 }
331 Value::List(items) => {
332 encode_size(items.len(), [0xD4, 0xD5, 0xD6], Some(0x90), out);
333 for item in items {
334 encode(item, out);
335 }
336 }
337 Value::Map(entries) => {
338 encode_size(entries.len(), [0xD8, 0xD9, 0xDA], Some(0xA0), out);
339 for (key, value) in entries {
340 encode(&Value::String(key.clone()), out);
341 encode(value, out);
342 }
343 }
344 Value::Struct { tag, fields } => {
345 let n = fields.len();
346 if n < 16 {
347 out.push(0xB0 | n as u8);
348 } else if n <= u8::MAX as usize {
349 out.push(0xDC);
350 out.push(n as u8);
351 } else {
352 out.push(0xDD);
353 out.extend_from_slice(&(n.min(u16::MAX as usize) as u16).to_be_bytes());
354 }
355 out.push(*tag);
356 for field in fields.iter().take(u16::MAX as usize) {
357 encode(field, out);
358 }
359 }
360 }
361}
362
363pub fn to_bytes(value: &Value) -> Vec<u8> {
365 let mut out = Vec::new();
366 encode(value, &mut out);
367 out
368}
369
370fn encode_int(i: i64, out: &mut Vec<u8>) {
371 if (-16..=127).contains(&i) {
372 out.push(i as i8 as u8);
373 } else if i8::try_from(i).is_ok() {
374 out.push(0xC8);
375 out.push(i as i8 as u8);
376 } else if let Ok(v) = i16::try_from(i) {
377 out.push(0xC9);
378 out.extend_from_slice(&v.to_be_bytes());
379 } else if let Ok(v) = i32::try_from(i) {
380 out.push(0xCA);
381 out.extend_from_slice(&v.to_be_bytes());
382 } else {
383 out.push(0xCB);
384 out.extend_from_slice(&i.to_be_bytes());
385 }
386}
387
388fn encode_size(len: usize, wide: [u8; 3], tiny: Option<u8>, out: &mut Vec<u8>) {
392 match tiny {
393 Some(base) if len < 16 => out.push(base | len as u8),
394 _ if len <= u8::MAX as usize => {
395 out.push(wide[0]);
396 out.push(len as u8);
397 }
398 _ if len <= u16::MAX as usize => {
399 out.push(wide[1]);
400 out.extend_from_slice(&(len as u16).to_be_bytes());
401 }
402 _ => {
403 out.push(wide[2]);
404 out.extend_from_slice(&(len.min(u32::MAX as usize) as u32).to_be_bytes());
405 }
406 }
407}
408
409pub fn chunk(message: &[u8]) -> Vec<u8> {
411 let mut out = Vec::with_capacity(message.len() + 4 + 2 * (message.len() / MAX_CHUNK_BYTES));
412 for piece in message.chunks(MAX_CHUNK_BYTES) {
413 out.extend_from_slice(&(piece.len() as u16).to_be_bytes());
414 out.extend_from_slice(piece);
415 }
416 out.extend_from_slice(&[0, 0]);
417 out
418}
419
420pub fn message_bytes(value: &Value) -> Vec<u8> {
422 chunk(&to_bytes(value))
423}
424
425#[derive(Debug, Clone, PartialEq, Eq)]
427pub enum FrameError {
428 TooLarge { limit: usize },
430}
431
432#[derive(Debug)]
440pub struct Dechunker {
441 input: Vec<u8>,
442 message: Vec<u8>,
443 limit: usize,
444}
445
446impl Dechunker {
447 pub fn new(limit: usize) -> Self {
448 Self {
449 input: Vec::new(),
450 message: Vec::new(),
451 limit,
452 }
453 }
454
455 pub fn push(&mut self, bytes: &[u8]) {
456 self.input.extend_from_slice(bytes);
457 }
458
459 pub fn pending(&self) -> usize {
461 self.input.len() + self.message.len()
462 }
463
464 pub fn next_message(&mut self) -> Result<Option<Vec<u8>>, FrameError> {
465 let mut consumed = 0usize;
466 let result = loop {
467 let rest = &self.input[consumed..];
468 if rest.len() < 2 {
469 break Ok(None);
470 }
471 let size = usize::from(u16::from_be_bytes([rest[0], rest[1]]));
472 if size == 0 {
473 consumed += 2;
474 if self.message.is_empty() {
475 continue; }
477 break Ok(Some(std::mem::take(&mut self.message)));
478 }
479 if self.message.len() + size > self.limit {
481 break Err(FrameError::TooLarge { limit: self.limit });
482 }
483 if rest.len() < 2 + size {
484 break Ok(None);
485 }
486 self.message.extend_from_slice(&rest[2..2 + size]);
487 consumed += 2 + size;
488 };
489 self.input.drain(..consumed);
490 result
491 }
492}