1use anyhow::{bail, ensure, Context, Result};
4
5const MAX_DEPTH: usize = 32;
6const MAX_ITEMS: usize = 100_000;
7
8#[derive(Debug, Clone, PartialEq)]
9pub enum Value {
10 Null,
11 Bool(bool),
12 Ubyte(u8),
13 Ushort(u16),
14 Uint(u32),
15 Ulong(u64),
16 Byte(i8),
17 Short(i16),
18 Int(i32),
19 Long(i64),
20 Float(f32),
21 Double(f64),
22 Char(char),
23 Timestamp(i64),
24 Uuid([u8; 16]),
25 Binary(Vec<u8>),
26 String(String),
27 Symbol(String),
28 Decimal(Vec<u8>),
29 List(Vec<Value>),
30 Map(Vec<(Value, Value)>),
31 Array(Vec<Value>),
32 Described(Box<Value>, Box<Value>),
33}
34
35impl Value {
36 pub fn as_u64(&self) -> Option<u64> {
37 match self {
38 Value::Ubyte(n) => Some(*n as u64),
39 Value::Ushort(n) => Some(*n as u64),
40 Value::Uint(n) => Some(*n as u64),
41 Value::Ulong(n) => Some(*n),
42 Value::Byte(n) if *n >= 0 => Some(*n as u64),
43 Value::Short(n) if *n >= 0 => Some(*n as u64),
44 Value::Int(n) if *n >= 0 => Some(*n as u64),
45 Value::Long(n) if *n >= 0 => Some(*n as u64),
46 _ => None,
47 }
48 }
49 pub fn as_str(&self) -> Option<&str> {
50 match self {
51 Value::String(s) | Value::Symbol(s) => Some(s),
52 _ => None,
53 }
54 }
55 pub fn as_bool(&self) -> Option<bool> {
56 match self {
57 Value::Bool(b) => Some(*b),
58 _ => None,
59 }
60 }
61 pub fn is_null(&self) -> bool {
62 matches!(self, Value::Null)
63 }
64 pub fn descriptor(&self) -> Option<u64> {
66 match self {
67 Value::Described(d, _) => d.as_u64().or_else(|| d.as_str().and_then(symbolic_code)),
68 _ => None,
69 }
70 }
71 pub fn fields(&self) -> &[Value] {
73 match self {
74 Value::Described(_, inner) => match inner.as_ref() {
75 Value::List(f) => f,
76 _ => &[],
77 },
78 _ => &[],
79 }
80 }
81 pub fn described(code: u64, fields: Vec<Value>) -> Value {
82 Value::Described(Box::new(Value::Ulong(code)), Box::new(Value::List(fields)))
83 }
84 pub fn sym(s: &str) -> Value {
85 Value::Symbol(s.to_owned())
86 }
87 pub fn str(s: &str) -> Value {
88 Value::String(s.to_owned())
89 }
90}
91
92pub fn field(v: &Value, i: usize) -> &Value {
94 v.fields().get(i).unwrap_or(&Value::Null)
95}
96
97fn symbolic_code(s: &str) -> Option<u64> {
98 Some(match s {
99 "amqp:open:list" => 0x10,
100 "amqp:begin:list" => 0x11,
101 "amqp:attach:list" => 0x12,
102 "amqp:flow:list" => 0x13,
103 "amqp:transfer:list" => 0x14,
104 "amqp:disposition:list" => 0x15,
105 "amqp:detach:list" => 0x16,
106 "amqp:end:list" => 0x17,
107 "amqp:close:list" => 0x18,
108 "amqp:error:list" => 0x1d,
109 "amqp:received:list" => 0x23,
110 "amqp:accepted:list" => 0x24,
111 "amqp:rejected:list" => 0x25,
112 "amqp:released:list" => 0x26,
113 "amqp:modified:list" => 0x27,
114 "amqp:source:list" => 0x28,
115 "amqp:target:list" => 0x29,
116 "amqp:sasl-mechanisms:list" => 0x40,
117 "amqp:sasl-init:list" => 0x41,
118 "amqp:sasl-outcome:list" => 0x44,
119 "amqp:header:list" => 0x70,
120 "amqp:delivery-annotations:map" => 0x71,
121 "amqp:message-annotations:map" => 0x72,
122 "amqp:properties:list" => 0x73,
123 "amqp:application-properties:map" => 0x74,
124 "amqp:data:binary" => 0x75,
125 "amqp:amqp-sequence:list" => 0x76,
126 "amqp:amqp-value:*" => 0x77,
127 "amqp:footer:map" => 0x78,
128 _ => return None,
129 })
130}
131
132struct Reader<'a> {
133 b: &'a [u8],
134 pos: usize,
135 items: usize,
136}
137
138impl Reader<'_> {
139 fn take(&mut self, n: usize) -> Result<&[u8]> {
140 let v = self
141 .b
142 .get(self.pos..self.pos.checked_add(n).context("length overflow")?)
143 .context("truncated AMQP value")?;
144 self.pos += n;
145 Ok(v)
146 }
147 fn u8(&mut self) -> Result<u8> {
148 Ok(self.take(1)?[0])
149 }
150 fn u32(&mut self) -> Result<u32> {
151 Ok(u32::from_be_bytes(self.take(4)?.try_into()?))
152 }
153 fn arr<const N: usize>(&mut self) -> Result<[u8; N]> {
154 Ok(self.take(N)?.try_into()?)
155 }
156
157 fn value(&mut self, depth: usize) -> Result<Value> {
158 let code = self.u8()?;
159 self.with_code(code, depth)
160 }
161
162 fn with_code(&mut self, code: u8, depth: usize) -> Result<Value> {
163 ensure!(depth <= MAX_DEPTH, "AMQP value nests too deeply");
164 self.items += 1;
165 ensure!(self.items <= MAX_ITEMS, "too many AMQP values");
166 Ok(match code {
167 0x00 => {
168 let d = self.value(depth + 1)?;
169 let v = self.value(depth + 1)?;
170 Value::Described(Box::new(d), Box::new(v))
171 }
172 0x40 => Value::Null,
173 0x41 => Value::Bool(true),
174 0x42 => Value::Bool(false),
175 0x56 => Value::Bool(self.u8()? != 0),
176 0x50 => Value::Ubyte(self.u8()?),
177 0x60 => Value::Ushort(u16::from_be_bytes(self.arr()?)),
178 0x70 => Value::Uint(self.u32()?),
179 0x52 => Value::Uint(self.u8()? as u32),
180 0x43 => Value::Uint(0),
181 0x80 => Value::Ulong(u64::from_be_bytes(self.arr()?)),
182 0x53 => Value::Ulong(self.u8()? as u64),
183 0x44 => Value::Ulong(0),
184 0x51 => Value::Byte(self.u8()? as i8),
185 0x61 => Value::Short(i16::from_be_bytes(self.arr()?)),
186 0x71 => Value::Int(i32::from_be_bytes(self.arr()?)),
187 0x54 => Value::Int(self.u8()? as i8 as i32),
188 0x81 => Value::Long(i64::from_be_bytes(self.arr()?)),
189 0x55 => Value::Long(self.u8()? as i8 as i64),
190 0x72 => Value::Float(f32::from_be_bytes(self.arr()?)),
191 0x82 => Value::Double(f64::from_be_bytes(self.arr()?)),
192 0x74 => Value::Decimal(self.take(4)?.to_vec()),
193 0x84 => Value::Decimal(self.take(8)?.to_vec()),
194 0x94 => Value::Decimal(self.take(16)?.to_vec()),
195 0x73 => Value::Char(char::from_u32(self.u32()?).context("invalid char")?),
196 0x83 => Value::Timestamp(i64::from_be_bytes(self.arr()?)),
197 0x98 => Value::Uuid(self.arr()?),
198 0xa0 | 0xb0 => {
199 let n = if code == 0xa0 {
200 self.u8()? as usize
201 } else {
202 self.u32()? as usize
203 };
204 Value::Binary(self.take(n)?.to_vec())
205 }
206 0xa1 | 0xb1 | 0xa3 | 0xb3 => {
207 let n = if code & 0xf0 == 0xa0 {
208 self.u8()? as usize
209 } else {
210 self.u32()? as usize
211 };
212 let s = std::str::from_utf8(self.take(n)?)
213 .context("string is not UTF-8")?
214 .to_owned();
215 if code & 0x0f == 1 {
216 Value::String(s)
217 } else {
218 Value::Symbol(s)
219 }
220 }
221 0x45 => Value::List(vec![]),
222 0xc0 | 0xd0 | 0xc1 | 0xd1 => {
223 let wide = code & 0xf0 == 0xd0;
224 let size = if wide {
225 self.u32()? as usize
226 } else {
227 self.u8()? as usize
228 };
229 let end = self
230 .pos
231 .checked_add(size)
232 .filter(|e| *e <= self.b.len())
233 .context("compound longer than its buffer")?;
234 let count = if wide {
235 self.u32()? as usize
236 } else {
237 self.u8()? as usize
238 };
239 ensure!(count <= MAX_ITEMS, "compound count too large");
240 let mut items = Vec::with_capacity(count.min(1024));
241 for _ in 0..count {
242 items.push(self.value(depth + 1)?);
243 }
244 ensure!(self.pos == end, "compound size does not match its contents");
245 if code & 0x0f == 0 {
246 Value::List(items)
247 } else {
248 ensure!(count % 2 == 0, "map with an odd count");
249 let mut m = Vec::with_capacity(items.len() / 2);
250 let mut it = items.into_iter();
251 while let (Some(k), Some(v)) = (it.next(), it.next()) {
252 m.push((k, v));
253 }
254 Value::Map(m)
255 }
256 }
257 0xe0 | 0xf0 => {
258 let wide = code == 0xf0;
259 let size = if wide {
260 self.u32()? as usize
261 } else {
262 self.u8()? as usize
263 };
264 let end = self
265 .pos
266 .checked_add(size)
267 .filter(|e| *e <= self.b.len())
268 .context("array longer than its buffer")?;
269 let count = if wide {
270 self.u32()? as usize
271 } else {
272 self.u8()? as usize
273 };
274 ensure!(count <= MAX_ITEMS, "array count too large");
275 let mut ctor = self.u8()?;
276 let mut descriptor = None;
277 if ctor == 0x00 {
278 descriptor = Some(self.value(depth + 1)?);
279 ctor = self.u8()?;
280 }
281 let mut items = Vec::with_capacity(count.min(1024));
282 for _ in 0..count {
283 let v = self.with_code(ctor, depth + 1)?;
284 items.push(match &descriptor {
285 Some(d) => Value::Described(Box::new(d.clone()), Box::new(v)),
286 None => v,
287 });
288 }
289 ensure!(self.pos == end, "array size does not match its contents");
290 Value::Array(items)
291 }
292 other => bail!("unknown AMQP type code 0x{other:02x}"),
293 })
294 }
295}
296
297pub fn decode(b: &[u8]) -> Result<(Value, usize)> {
299 let mut r = Reader {
300 b,
301 pos: 0,
302 items: 0,
303 };
304 let v = r.value(0)?;
305 Ok((v, r.pos))
306}
307
308pub fn decode_all(b: &[u8]) -> Result<Vec<Value>> {
310 let mut r = Reader {
311 b,
312 pos: 0,
313 items: 0,
314 };
315 let mut out = Vec::new();
316 while r.pos < b.len() {
317 out.push(r.value(0)?);
318 }
319 Ok(out)
320}
321
322fn sized(out: &mut Vec<u8>, short: u8, long: u8, body: &[u8], count: usize) {
323 if body.len() < 255 && count < 256 {
324 out.push(short);
325 out.push((body.len() + 1) as u8);
326 out.push(count as u8);
327 } else {
328 out.push(long);
329 out.extend(((body.len() + 4) as u32).to_be_bytes());
330 out.extend((count as u32).to_be_bytes());
331 }
332 out.extend(body);
333}
334
335fn element(v: &Value) -> (u8, Vec<u8>) {
337 let mut full = Vec::new();
338 encode_into(v, &mut full);
339 match v {
340 Value::String(s) => (
342 0xb1,
343 [&(s.len() as u32).to_be_bytes()[..], s.as_bytes()].concat(),
344 ),
345 Value::Symbol(s) => (
346 0xb3,
347 [&(s.len() as u32).to_be_bytes()[..], s.as_bytes()].concat(),
348 ),
349 Value::Binary(b) => (0xb0, [&(b.len() as u32).to_be_bytes()[..], b].concat()),
350 Value::Uint(n) => (0x70, n.to_be_bytes().to_vec()),
351 Value::Ulong(n) => (0x80, n.to_be_bytes().to_vec()),
352 Value::Int(n) => (0x71, n.to_be_bytes().to_vec()),
353 Value::Long(n) => (0x81, n.to_be_bytes().to_vec()),
354 Value::Bool(b) => (0x56, vec![*b as u8]),
355 _ => (full[0], full[1..].to_vec()),
356 }
357}
358
359pub fn encode_into(v: &Value, out: &mut Vec<u8>) {
360 match v {
361 Value::Null => out.push(0x40),
362 Value::Bool(true) => out.push(0x41),
363 Value::Bool(false) => out.push(0x42),
364 Value::Ubyte(n) => out.extend([0x50, *n]),
365 Value::Ushort(n) => {
366 out.push(0x60);
367 out.extend(n.to_be_bytes());
368 }
369 Value::Uint(0) => out.push(0x43),
370 Value::Uint(n) if *n < 256 => out.extend([0x52, *n as u8]),
371 Value::Uint(n) => {
372 out.push(0x70);
373 out.extend(n.to_be_bytes());
374 }
375 Value::Ulong(0) => out.push(0x44),
376 Value::Ulong(n) if *n < 256 => out.extend([0x53, *n as u8]),
377 Value::Ulong(n) => {
378 out.push(0x80);
379 out.extend(n.to_be_bytes());
380 }
381 Value::Byte(n) => out.extend([0x51, *n as u8]),
382 Value::Short(n) => {
383 out.push(0x61);
384 out.extend(n.to_be_bytes());
385 }
386 Value::Int(n) if (-128..128).contains(n) => out.extend([0x54, *n as i8 as u8]),
387 Value::Int(n) => {
388 out.push(0x71);
389 out.extend(n.to_be_bytes());
390 }
391 Value::Long(n) if (-128..128).contains(n) => out.extend([0x55, *n as i8 as u8]),
392 Value::Long(n) => {
393 out.push(0x81);
394 out.extend(n.to_be_bytes());
395 }
396 Value::Float(f) => {
397 out.push(0x72);
398 out.extend(f.to_be_bytes());
399 }
400 Value::Double(f) => {
401 out.push(0x82);
402 out.extend(f.to_be_bytes());
403 }
404 Value::Decimal(b) => {
405 out.push(match b.len() {
406 4 => 0x74,
407 8 => 0x84,
408 _ => 0x94,
409 });
410 out.extend(b);
411 }
412 Value::Char(c) => {
413 out.push(0x73);
414 out.extend((*c as u32).to_be_bytes());
415 }
416 Value::Timestamp(t) => {
417 out.push(0x83);
418 out.extend(t.to_be_bytes());
419 }
420 Value::Uuid(u) => {
421 out.push(0x98);
422 out.extend(u);
423 }
424 Value::Binary(b) => var(out, 0xa0, 0xb0, b),
425 Value::String(s) => var(out, 0xa1, 0xb1, s.as_bytes()),
426 Value::Symbol(s) => var(out, 0xa3, 0xb3, s.as_bytes()),
427 Value::List(items) if items.is_empty() => out.push(0x45),
428 Value::List(items) => {
429 let mut body = Vec::new();
430 for i in items {
431 encode_into(i, &mut body);
432 }
433 sized(out, 0xc0, 0xd0, &body, items.len());
434 }
435 Value::Map(pairs) => {
436 let mut body = Vec::new();
437 for (k, v) in pairs {
438 encode_into(k, &mut body);
439 encode_into(v, &mut body);
440 }
441 sized(out, 0xc1, 0xd1, &body, pairs.len() * 2);
442 }
443 Value::Array(items) => {
444 let (ctor, mut body) = match items.first() {
445 None => (0x40, Vec::new()),
446 Some(first) => (element(first).0, Vec::new()),
447 };
448 for i in items {
449 body.extend(element(i).1);
450 }
451 let mut all = vec![ctor];
452 all.extend(body);
453 if all.len() < 255 && items.len() < 256 {
455 out.push(0xe0);
456 out.push((all.len() + 1) as u8);
457 out.push(items.len() as u8);
458 } else {
459 out.push(0xf0);
460 out.extend(((all.len() + 4) as u32).to_be_bytes());
461 out.extend((items.len() as u32).to_be_bytes());
462 }
463 out.extend(all);
464 }
465 Value::Described(d, v) => {
466 out.push(0x00);
467 encode_into(d, out);
468 encode_into(v, out);
469 }
470 }
471}
472
473fn var(out: &mut Vec<u8>, short: u8, long: u8, b: &[u8]) {
474 if b.len() < 256 {
475 out.extend([short, b.len() as u8]);
476 } else {
477 out.push(long);
478 out.extend((b.len() as u32).to_be_bytes());
479 }
480 out.extend(b);
481}
482
483pub fn encode(v: &Value) -> Vec<u8> {
484 let mut out = Vec::new();
485 encode_into(v, &mut out);
486 out
487}