libdd_trace_utils/msgpack_encoder/v04/
mod.rs

1// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::span::{Span, SpanText};
5use rmp::encode::{write_array_len, ByteBuf, RmpWrite, ValueWriteError};
6
7mod span;
8
9#[inline(always)]
10fn to_writer<W: RmpWrite, T: SpanText, S: AsRef<[Span<T>]>>(
11    writer: &mut W,
12    traces: &[S],
13) -> Result<(), ValueWriteError<W::Error>> {
14    write_array_len(writer, traces.len() as u32)?;
15    for trace in traces {
16        write_array_len(writer, trace.as_ref().len() as u32)?;
17        for span in trace.as_ref() {
18            span::encode_span(writer, span)?;
19        }
20    }
21
22    Ok(())
23}
24
25/// Encodes a collection of traces into a slice of bytes.
26///
27/// # Arguments
28///
29/// * `slice` - A mutable reference to a byte slice.
30/// * `traces` - A reference to a slice of spans.
31///
32/// # Returns
33///
34/// * `Ok(())` - If encoding succeeds.
35/// * `Err(ValueWriteError)` - If encoding fails.
36///
37/// # Errors
38///
39/// This function will return an error if:
40/// - The array length for trace count or span count cannot be written.
41/// - Any span cannot be encoded.
42///
43/// # Examples
44///
45/// ```
46/// use libdd_trace_utils::msgpack_encoder::v04::write_to_slice;
47/// use libdd_trace_utils::span::Span;
48///
49/// let mut buffer = vec![0u8; 1024];
50/// let span = Span {
51///     name: "test-span",
52///     ..Default::default()
53/// };
54/// let traces = vec![vec![span]];
55///
56/// write_to_slice(&mut &mut buffer[..], &traces).expect("Encoding failed");
57/// ```
58pub fn write_to_slice<T: SpanText, S: AsRef<[Span<T>]>>(
59    slice: &mut &mut [u8],
60    traces: &[S],
61) -> Result<(), ValueWriteError> {
62    to_writer(slice, traces)
63}
64
65/// Serializes traces into a vector of bytes with a default capacity of 0.
66///
67/// # Arguments
68///
69/// * `traces` - A reference to a slice of spans.
70///
71/// # Returns
72///
73/// * `Vec<u8>` - A vector containing encoded traces.
74///
75/// # Examples
76///
77/// ```
78/// use libdd_trace_utils::msgpack_encoder::v04::to_vec;
79/// use libdd_trace_utils::span::Span;
80///
81/// let span = Span {
82///     name: "test-span",
83///     ..Default::default()
84/// };
85/// let traces = vec![vec![span]];
86/// let encoded = to_vec(&traces);
87///
88/// assert!(!encoded.is_empty());
89/// ```
90pub fn to_vec<T: SpanText, S: AsRef<[Span<T>]>>(traces: &[S]) -> Vec<u8> {
91    to_vec_with_capacity(traces, 0)
92}
93
94/// Serializes traces into a vector of bytes with specified capacity.
95///
96/// # Arguments
97///
98/// * `traces` - A reference to a slice of spans.
99/// * `capacity` - Desired initial capacity of the resulting vector.
100///
101/// # Returns
102///
103/// * `Vec<u8>` - A vector containing encoded traces.
104///
105/// # Examples
106///
107/// ```
108/// use libdd_trace_utils::msgpack_encoder::v04::to_vec_with_capacity;
109/// use libdd_trace_utils::span::Span;
110///
111/// let span = Span {
112///     name: "test-span",
113///     ..Default::default()
114/// };
115/// let traces = vec![vec![span]];
116/// let encoded = to_vec_with_capacity(&traces, 1024);
117///
118/// assert!(encoded.capacity() >= 1024);
119/// ```
120pub fn to_vec_with_capacity<T: SpanText, S: AsRef<[Span<T>]>>(
121    traces: &[S],
122    capacity: u32,
123) -> Vec<u8> {
124    let mut buf = ByteBuf::with_capacity(capacity as usize);
125    #[allow(clippy::expect_used)]
126    to_writer(&mut buf, traces).expect("infallible: the error is std::convert::Infallible");
127    buf.into_vec()
128}
129
130struct CountLength(u32);
131
132impl std::io::Write for CountLength {
133    #[inline]
134    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
135        self.write_all(buf)?;
136        Ok(buf.len())
137    }
138
139    #[inline]
140    fn flush(&mut self) -> std::io::Result<()> {
141        Ok(())
142    }
143
144    #[inline]
145    fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
146        self.0 += buf.len() as u32;
147        Ok(())
148    }
149}
150
151/// Computes the number of bytes required to encode the given traces.
152///
153/// This does not allocate any actual buffer, but simulates writing in order to measure
154/// the encoded size of the traces.
155///
156/// # Arguments
157///
158/// * `traces` - A reference to a slice of spans.
159///
160/// # Returns
161///
162/// * `u32` - The number of bytes that would be written by the encoder.
163///
164/// # Examples
165///
166/// ```
167/// use libdd_trace_utils::msgpack_encoder::v04::to_len;
168/// use libdd_trace_utils::span::Span;
169///
170/// let span = Span {
171///     name: "test-span",
172///     ..Default::default()
173/// };
174/// let traces = vec![vec![span]];
175/// let encoded_len = to_len(&traces);
176///
177/// assert!(encoded_len > 0);
178/// ```
179pub fn to_len<T: SpanText, S: AsRef<[Span<T>]>>(traces: &[S]) -> u32 {
180    let mut counter = CountLength(0);
181    #[allow(clippy::expect_used)]
182    to_writer(&mut counter, traces).expect("infallible: CountLength never fails");
183    counter.0
184}