1use alloc::{string::String, vec::Vec};
2use core::{fmt, str};
3use smallvec::SmallVec;
4use tracing_core::Level;
5
6use crate::{BinaryFrameKind, CallsiteKind, FieldValue, InlineString, Timestamp};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct DecodedCallsiteMetadata {
11 pub id: u32,
12 pub name: String,
13 pub target: String,
14 pub level: Level,
15 pub file: Option<String>,
16 pub line: Option<u32>,
17 pub module_path: Option<String>,
18 pub fields: SmallVec<[String; 8]>,
19 pub kind: CallsiteKind,
20}
21
22#[derive(Clone, Debug, PartialEq)]
24pub struct DecodedField {
25 pub name: String,
26 pub value: FieldValue,
27}
28
29pub type DecodedFields = SmallVec<[DecodedField; 8]>;
31
32#[derive(Clone, Debug, PartialEq)]
34pub struct DecodedSpanSnapshot {
35 pub id: u64,
36 pub metadata_id: u32,
37 pub name: String,
38 pub target: String,
39 pub level: Level,
40 pub fields: DecodedFields,
41}
42
43#[derive(Clone, Debug, PartialEq)]
45pub struct DecodedRecord {
46 pub timestamp: Timestamp,
47 pub metadata_id: u32,
48 pub current_span_id: u64,
49 pub fields: DecodedFields,
50 pub current_span: Option<DecodedSpanSnapshot>,
51 pub spans: SmallVec<[DecodedSpanSnapshot; 4]>,
52}
53
54#[derive(Clone, Debug, PartialEq)]
56#[allow(clippy::large_enum_variant)]
57pub enum DecodedBinaryFrame {
58 Metadata(DecodedCallsiteMetadata),
59 Event(DecodedRecord),
60}
61
62#[derive(Clone, Debug, PartialEq, Eq)]
64pub enum BinaryDecodeError {
65 UnexpectedEof,
66 InvalidFrameKind(u8),
67 InvalidCallsiteKind(u8),
68 InvalidLevel(u8),
69 InvalidFieldType(u8),
70 InvalidUtf8,
71}
72
73impl fmt::Display for BinaryDecodeError {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 match self {
76 Self::UnexpectedEof => f.write_str("unexpected end of binary frame"),
77 Self::InvalidFrameKind(kind) => write!(f, "invalid frame kind `{kind}`"),
78 Self::InvalidCallsiteKind(kind) => write!(f, "invalid callsite kind `{kind}`"),
79 Self::InvalidLevel(level) => write!(f, "invalid level code `{level}`"),
80 Self::InvalidFieldType(kind) => write!(f, "invalid field type `{kind}`"),
81 Self::InvalidUtf8 => f.write_str("invalid utf-8 string in binary frame"),
82 }
83 }
84}
85
86pub fn decode_binary_frame(input: &[u8]) -> Result<(DecodedBinaryFrame, &[u8]), BinaryDecodeError> {
91 let (frame_kind, rest) = take_u8(input)?;
92 let (payload_len, rest) = take_u32(rest)?;
93 let payload_len = payload_len as usize;
94 if rest.len() < payload_len {
95 return Err(BinaryDecodeError::UnexpectedEof);
96 }
97 let (payload, remaining) = rest.split_at(payload_len);
98 let frame = match frame_kind {
99 kind if kind == BinaryFrameKind::Metadata as u8 => {
100 DecodedBinaryFrame::Metadata(decode_metadata_payload(payload)?)
101 }
102 kind if kind == BinaryFrameKind::Event as u8 => {
103 DecodedBinaryFrame::Event(decode_event_payload(payload)?)
104 }
105 other => return Err(BinaryDecodeError::InvalidFrameKind(other)),
106 };
107 Ok((frame, remaining))
108}
109
110fn decode_metadata_payload(mut input: &[u8]) -> Result<DecodedCallsiteMetadata, BinaryDecodeError> {
111 let (id, rest) = take_u32(input)?;
112 input = rest;
113 let (kind, rest) = take_u8(input)?;
114 input = rest;
115 let kind = match kind {
116 1 => CallsiteKind::Event,
117 2 => CallsiteKind::Span,
118 other => return Err(BinaryDecodeError::InvalidCallsiteKind(other)),
119 };
120 let (level_code, rest) = take_u8(input)?;
121 input = rest;
122 let level = decode_level(level_code)?;
123 let (file, rest) = take_optional_string(input)?;
124 input = rest;
125 let (line, rest) = take_optional_u32(input)?;
126 input = rest;
127 let (module_path, rest) = take_optional_string(input)?;
128 input = rest;
129 let (name, rest) = take_string(input)?;
130 input = rest;
131 let (target, rest) = take_string(input)?;
132 input = rest;
133 let (field_count, mut rest) = take_u16(input)?;
134 let mut fields = SmallVec::new();
135 for _ in 0..field_count {
136 let (field, next) = take_string(rest)?;
137 rest = next;
138 fields.push(field);
139 }
140
141 Ok(DecodedCallsiteMetadata {
142 id,
143 name,
144 target,
145 level,
146 file,
147 line,
148 module_path,
149 fields,
150 kind,
151 })
152}
153
154fn decode_event_payload(mut input: &[u8]) -> Result<DecodedRecord, BinaryDecodeError> {
155 let (unix_seconds, rest) = take_u64(input)?;
156 input = rest;
157 let (subsec_nanos, rest) = take_u32(input)?;
158 input = rest;
159 let (metadata_id, rest) = take_u32(input)?;
160 input = rest;
161 let (current_span_id, rest) = take_u64(input)?;
162 input = rest;
163 let (fields, rest) = take_fields(input)?;
164 input = rest;
165 let (has_current_span, rest) = take_u8(input)?;
166 input = rest;
167 let current_span = if has_current_span == 1 {
168 let (span, rest) = take_span(input)?;
169 input = rest;
170 Some(span)
171 } else {
172 None
173 };
174
175 let (span_count, mut rest) = take_u16(input)?;
176 let mut spans = SmallVec::new();
177 for _ in 0..span_count {
178 let (span, next) = take_span(rest)?;
179 rest = next;
180 spans.push(span);
181 }
182
183 Ok(DecodedRecord {
184 timestamp: Timestamp::new(unix_seconds, subsec_nanos),
185 metadata_id,
186 current_span_id,
187 fields,
188 current_span,
189 spans,
190 })
191}
192
193fn take_span(input: &[u8]) -> Result<(DecodedSpanSnapshot, &[u8]), BinaryDecodeError> {
194 let (id, rest) = take_u64(input)?;
195 let (metadata_id, rest) = take_u32(rest)?;
196 let (level_code, rest) = take_u8(rest)?;
197 let level = decode_level(level_code)?;
198 let (name, rest) = take_string(rest)?;
199 let (target, rest) = take_string(rest)?;
200 let (fields, rest) = take_fields(rest)?;
201
202 Ok((
203 DecodedSpanSnapshot {
204 id,
205 metadata_id,
206 name,
207 target,
208 level,
209 fields,
210 },
211 rest,
212 ))
213}
214
215fn take_fields(input: &[u8]) -> Result<(DecodedFields, &[u8]), BinaryDecodeError> {
216 let (field_count, mut input) = take_u16(input)?;
217 let mut fields = SmallVec::new();
218 for _ in 0..field_count {
219 let (name, rest) = take_string(input)?;
220 input = rest;
221 let (value, rest) = take_field_value(input)?;
222 input = rest;
223 fields.push(DecodedField { name, value });
224 }
225 Ok((fields, input))
226}
227
228fn take_field_value(input: &[u8]) -> Result<(FieldValue, &[u8]), BinaryDecodeError> {
229 let (kind, input) = take_u8(input)?;
230 match kind {
231 1 => Ok((FieldValue::Bool(false), input)),
232 2 => Ok((FieldValue::Bool(true), input)),
233 3 => {
234 let (value, input) = take_i64(input)?;
235 Ok((FieldValue::I64(value), input))
236 }
237 4 => {
238 let (value, input) = take_u64(input)?;
239 Ok((FieldValue::U64(value), input))
240 }
241 5 => {
242 let (value, input) = take_i128(input)?;
243 Ok((FieldValue::I128(value), input))
244 }
245 6 => {
246 let (value, input) = take_u128(input)?;
247 Ok((FieldValue::U128(value), input))
248 }
249 7 => {
250 let (value, input) = take_f64(input)?;
251 Ok((FieldValue::F64(value), input))
252 }
253 8 => {
254 let (value, input) = take_string(input)?;
255 Ok((FieldValue::Str(InlineString::from(value)), input))
256 }
257 9 => {
258 let (value, input) = take_string(input)?;
259 Ok((FieldValue::Debug(InlineString::from(value)), input))
260 }
261 10 => {
262 let (value, input) = take_bytes(input)?;
263 Ok((FieldValue::Bytes(value), input))
264 }
265 other => Err(BinaryDecodeError::InvalidFieldType(other)),
266 }
267}
268
269fn take_u8(input: &[u8]) -> Result<(u8, &[u8]), BinaryDecodeError> {
270 let Some((first, rest)) = input.split_first() else {
271 return Err(BinaryDecodeError::UnexpectedEof);
272 };
273 Ok((*first, rest))
274}
275
276fn take_u16(input: &[u8]) -> Result<(u16, &[u8]), BinaryDecodeError> {
277 if input.len() < 2 {
278 return Err(BinaryDecodeError::UnexpectedEof);
279 }
280 let (bytes, rest) = input.split_at(2);
281 Ok((u16::from_le_bytes([bytes[0], bytes[1]]), rest))
282}
283
284fn take_u32(input: &[u8]) -> Result<(u32, &[u8]), BinaryDecodeError> {
285 if input.len() < 4 {
286 return Err(BinaryDecodeError::UnexpectedEof);
287 }
288 let (bytes, rest) = input.split_at(4);
289 Ok((
290 u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
291 rest,
292 ))
293}
294
295fn take_u64(input: &[u8]) -> Result<(u64, &[u8]), BinaryDecodeError> {
296 if input.len() < 8 {
297 return Err(BinaryDecodeError::UnexpectedEof);
298 }
299 let (bytes, rest) = input.split_at(8);
300 Ok((
301 u64::from_le_bytes([
302 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
303 ]),
304 rest,
305 ))
306}
307
308fn take_i64(input: &[u8]) -> Result<(i64, &[u8]), BinaryDecodeError> {
309 let (value, rest) = take_u64(input)?;
310 Ok((value as i64, rest))
311}
312
313fn take_u128(input: &[u8]) -> Result<(u128, &[u8]), BinaryDecodeError> {
314 if input.len() < 16 {
315 return Err(BinaryDecodeError::UnexpectedEof);
316 }
317 let (bytes, rest) = input.split_at(16);
318 let mut array = [0u8; 16];
319 array.copy_from_slice(bytes);
320 Ok((u128::from_le_bytes(array), rest))
321}
322
323fn take_i128(input: &[u8]) -> Result<(i128, &[u8]), BinaryDecodeError> {
324 let (value, rest) = take_u128(input)?;
325 Ok((value as i128, rest))
326}
327
328fn take_f64(input: &[u8]) -> Result<(f64, &[u8]), BinaryDecodeError> {
329 let (value, rest) = take_u64(input)?;
330 Ok((f64::from_le_bytes(value.to_le_bytes()), rest))
331}
332
333fn take_bytes(input: &[u8]) -> Result<(Vec<u8>, &[u8]), BinaryDecodeError> {
334 let (len, input) = take_u32(input)?;
335 let len = len as usize;
336 if input.len() < len {
337 return Err(BinaryDecodeError::UnexpectedEof);
338 }
339 let (bytes, rest) = input.split_at(len);
340 Ok((bytes.to_vec(), rest))
341}
342
343fn take_string(input: &[u8]) -> Result<(String, &[u8]), BinaryDecodeError> {
344 let (len, input) = take_u32(input)?;
345 let len = len as usize;
346 if input.len() < len {
347 return Err(BinaryDecodeError::UnexpectedEof);
348 }
349 let (bytes, rest) = input.split_at(len);
350 let value = str::from_utf8(bytes).map_err(|_| BinaryDecodeError::InvalidUtf8)?;
351 Ok((value.into(), rest))
352}
353
354fn take_optional_string(input: &[u8]) -> Result<(Option<String>, &[u8]), BinaryDecodeError> {
355 let (present, input) = take_u8(input)?;
356 if present == 1 {
357 let (value, rest) = take_string(input)?;
358 Ok((Some(value), rest))
359 } else {
360 Ok((None, input))
361 }
362}
363
364fn take_optional_u32(input: &[u8]) -> Result<(Option<u32>, &[u8]), BinaryDecodeError> {
365 let (present, input) = take_u8(input)?;
366 if present == 1 {
367 let (value, rest) = take_u32(input)?;
368 Ok((Some(value), rest))
369 } else {
370 Ok((None, input))
371 }
372}
373
374fn decode_level(code: u8) -> Result<Level, BinaryDecodeError> {
375 match code {
376 1 => Ok(Level::ERROR),
377 2 => Ok(Level::WARN),
378 3 => Ok(Level::INFO),
379 4 => Ok(Level::DEBUG),
380 5 => Ok(Level::TRACE),
381 other => Err(BinaryDecodeError::InvalidLevel(other)),
382 }
383}
384
385#[cfg(test)]
386mod tests {
387 use alloc::vec;
388
389 use super::*;
390 use crate::{
391 CallsiteMetadata, EncodeConfig, FieldValue, OwnedField, OwnedRecord, SpanSnapshot,
392 encode_binary_metadata, encode_binary_record,
393 };
394
395 #[test]
396 fn decodes_binary_roundtrip() {
397 let metadata = CallsiteMetadata {
398 id: 11,
399 name: "request",
400 target: "app::http",
401 level: Level::INFO,
402 file: Some("src/main.rs"),
403 line: Some(8),
404 module_path: Some("app::http"),
405 fields: SmallVec::from_slice(&["message", "answer"]),
406 kind: CallsiteKind::Event,
407 };
408 let record = OwnedRecord {
409 timestamp: Timestamp::new(10, 20),
410 metadata_id: 11,
411 name: "request",
412 target: "app::http",
413 level: Level::INFO,
414 fields: SmallVec::from_vec(vec![
415 OwnedField {
416 name: "message",
417 value: FieldValue::Str("ok".into()),
418 },
419 OwnedField {
420 name: "answer",
421 value: FieldValue::U64(42),
422 },
423 ]),
424 current_span: Some(SpanSnapshot {
425 id: 77,
426 metadata_id: 2,
427 name: "span",
428 target: "app::http",
429 level: Level::INFO,
430 fields: SmallVec::new(),
431 }),
432 spans: SmallVec::new(),
433 };
434
435 let mut metadata_frame = Vec::new();
436 let mut event_frame = Vec::new();
437 encode_binary_metadata(&metadata, &mut metadata_frame);
438 encode_binary_record(EncodeConfig::default(), &record, &mut event_frame);
439
440 let mut stream = Vec::new();
441 stream.extend_from_slice(&metadata_frame);
442 stream.extend_from_slice(&event_frame);
443
444 let (first, rest) = decode_binary_frame(&stream).unwrap();
445 let (second, rest) = decode_binary_frame(rest).unwrap();
446 assert!(rest.is_empty());
447
448 match first {
449 DecodedBinaryFrame::Metadata(frame) => {
450 assert_eq!(frame.id, 11);
451 assert_eq!(frame.name, "request");
452 assert_eq!(frame.target, "app::http");
453 }
454 _ => panic!("expected metadata frame"),
455 }
456
457 match second {
458 DecodedBinaryFrame::Event(frame) => {
459 assert_eq!(frame.metadata_id, 11);
460 assert_eq!(frame.fields.len(), 2);
461 assert_eq!(frame.current_span.unwrap().id, 77);
462 }
463 _ => panic!("expected event frame"),
464 }
465 }
466}