Skip to main content

libdd_profiling_protobuf/
function.rs

1// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
2// SPDX-License-Identifier: Apache-2.0
3
4use super::{Record, StringOffset, Value, WireType, NO_OPT_ZERO, OPT_ZERO};
5use std::io::{self, Write};
6
7/// Represents a function in a profile. Omits the start line because it's not
8/// useful to Datadog right now, so we save the bytes/ops.
9#[repr(C)]
10#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
11#[cfg_attr(feature = "bolero", derive(bolero::generator::TypeGenerator))]
12pub struct Function {
13    /// Unique nonzero id for the function.
14    pub id: Record<u64, 1, NO_OPT_ZERO>,
15    /// Name of the function, in human-readable form if available.
16    pub name: Record<StringOffset, 2, OPT_ZERO>,
17    /// Name of the function, as identified by the system.
18    /// For instance, it can be a C++ mangled name.
19    pub system_name: Record<StringOffset, 3, OPT_ZERO>,
20    /// Source file containing the function.
21    pub filename: Record<StringOffset, 4, OPT_ZERO>,
22}
23
24/// # Safety
25/// The Default implementation will return all zero-representations.
26unsafe impl Value for Function {
27    const WIRE_TYPE: WireType = WireType::LengthDelimited;
28
29    fn proto_len(&self) -> u64 {
30        self.id.proto_len()
31            + self.name.proto_len()
32            + self.system_name.proto_len()
33            + self.filename.proto_len()
34    }
35
36    fn encode<W: Write>(&self, writer: &mut W) -> io::Result<()> {
37        self.id.encode(writer)?;
38        self.name.encode(writer)?;
39        self.system_name.encode(writer)?;
40        self.filename.encode(writer)
41    }
42}
43
44#[cfg(feature = "prost_impls")]
45impl From<&Function> for crate::prost_impls::Function {
46    fn from(value: &Function) -> Self {
47        // If the prost file is regenerated, this may pick up new members,
48        // such as start_line.
49        #[allow(clippy::needless_update)]
50        Self {
51            id: value.id.value,
52            name: value.name.value.into(),
53            system_name: value.system_name.value.into(),
54            filename: value.filename.value.into(),
55            ..Self::default()
56        }
57    }
58}
59
60#[cfg(feature = "prost_impls")]
61impl From<Function> for crate::prost_impls::Function {
62    fn from(value: Function) -> Self {
63        Self::from(&value)
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use crate::prost_impls;
71    use prost::Message;
72
73    #[test]
74    fn roundtrip() {
75        fn test(function: &Function) {
76            let mut buffer = Vec::new();
77            let prost_function = prost_impls::Function::from(function);
78
79            function.encode(&mut buffer).unwrap();
80            let roundtrip = prost_impls::Function::decode(buffer.as_slice()).unwrap();
81            assert_eq!(prost_function, roundtrip);
82
83            // This doesn't need to strictly be true, but it currently it is
84            // true and makes testing easier.
85            let mut buffer2 = Vec::new();
86            prost_function.encode(&mut buffer2).unwrap();
87            let roundtrip2 = prost_impls::Function::decode(buffer2.as_slice()).unwrap();
88            assert_eq!(roundtrip, roundtrip2);
89        }
90
91        bolero::check!().with_type::<Function>().for_each(test);
92    }
93}