veecle_telemetry/protocol/
transient.rs

1//! Type aliases for transient usage (with `format_args!` support).
2//!
3//! These aliases use [`Value`] which may contain non-Send types like `format_args!`.
4//! Use these for local telemetry operations that don't need to cross thread boundaries.
5//!
6//! See the [main protocol module][super] docs for more details on the protocol modules provided.
7
8use crate::protocol::base;
9use serde::Serialize;
10
11/// Transient storage family using borrowed data.
12///
13/// This family uses references for zero-copy operation, suitable for
14/// local telemetry that doesn't need to cross thread boundaries.
15#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
16pub struct Transient;
17
18impl base::Sealed for Transient {}
19impl base::StorageFamily for Transient {
20    type String<'a>
21        = &'a str
22    where
23        Self: 'a;
24
25    type List<'a, T: Clone + core::fmt::Debug + serde::Serialize + 'a>
26        = &'a [T]
27    where
28        Self: 'a;
29
30    type Value<'a>
31        = Value<'a>
32    where
33        Self: 'a;
34}
35
36// Re-export non-generic types for convenience.
37pub use base::{
38    ProcessId, Severity, SpanAddLinkMessage, SpanCloseMessage, SpanContext, SpanEnterMessage,
39    SpanExitMessage, SpanId, ThreadId, TimeSyncMessage,
40};
41
42/// Key-value pair with transient value (supports `format_args!`).
43pub type KeyValue<'a> = base::KeyValue<'a, Transient>;
44/// Instance message with transient values (supports `format_args!`).
45pub type InstanceMessage<'a> = base::InstanceMessage<'a, Transient>;
46/// Telemetry message with transient values (supports `format_args!`).
47pub type TelemetryMessage<'a> = base::TelemetryMessage<'a, Transient>;
48/// Log message with transient values (supports `format_args!`).
49pub type LogMessage<'a> = base::LogMessage<'a, Transient>;
50/// Tracing message with transient values (supports `format_args!`).
51pub type TracingMessage<'a> = base::TracingMessage<'a, Transient>;
52/// Span create message with transient values (supports `format_args!`).
53pub type SpanCreateMessage<'a> = base::SpanCreateMessage<'a, Transient>;
54/// Span set attribute message with transient values (supports `format_args!`).
55pub type SpanSetAttributeMessage<'a> = base::SpanSetAttributeMessage<'a, Transient>;
56/// Span add event message with transient values (supports `format_args!`).
57pub type SpanAddEventMessage<'a> = base::SpanAddEventMessage<'a, Transient>;
58
59/// A transient value that can be stored in a telemetry attribute.
60///
61/// This enum represents values that may contain non-Send types like `format_args!`,
62/// making them suitable for local use but not for sending across threads.
63///
64/// # Examples
65///
66/// ```rust
67/// use veecle_telemetry::protocol::transient::Value;
68///
69/// // Create values of different types
70/// let text = Value::String("hello world");
71/// let number = Value::I64(42);
72/// let flag = Value::Bool(true);
73/// let rating = Value::F64(4.5);
74/// ```
75#[derive(Clone, Debug, Serialize)]
76pub enum Value<'a> {
77    /// A string value
78    String(&'a str),
79
80    /// A `format_args!` call.
81    #[serde(rename(serialize = "String"))]
82    Formatted(core::fmt::Arguments<'a>),
83
84    /// A boolean value
85    Bool(bool),
86
87    /// A 64-bit signed integer
88    I64(i64),
89
90    /// A 64-bit floating-point number
91    F64(f64),
92}
93
94impl<'a> core::fmt::Display for Value<'a> {
95    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
96        match self {
97            // For strings, debug print so they will get delimiters, since we are explicitly
98            // representing strings rather than directly human-targeted text, and they will be used
99            // in situations where knowing where the string ends is important.
100            Self::String(value) => write!(f, "{value:?}"),
101            Self::Formatted(value) => write!(f, "{value:?}"),
102            Self::Bool(value) => write!(f, "{value}"),
103            Self::I64(value) => write!(f, "{value}"),
104            Self::F64(value) => write!(f, "{value}"),
105        }
106    }
107}
108
109impl<'a> From<&'a str> for Value<'a> {
110    fn from(value: &'a str) -> Self {
111        Value::String(value)
112    }
113}
114
115impl<'a> From<&'a &str> for Value<'a> {
116    fn from(value: &'a &str) -> Self {
117        Value::String(value)
118    }
119}
120
121#[cfg(feature = "alloc")]
122impl<'a> From<&'a alloc::string::String> for Value<'a> {
123    fn from(value: &'a alloc::string::String) -> Self {
124        Value::String(value)
125    }
126}
127
128impl<'a> From<core::fmt::Arguments<'a>> for Value<'a> {
129    fn from(value: core::fmt::Arguments<'a>) -> Self {
130        Value::Formatted(value)
131    }
132}
133
134impl<'a> From<&core::fmt::Arguments<'a>> for Value<'a> {
135    fn from(value: &core::fmt::Arguments<'a>) -> Self {
136        Value::Formatted(*value)
137    }
138}
139
140impl<'a> From<bool> for Value<'a> {
141    fn from(value: bool) -> Self {
142        Value::Bool(value)
143    }
144}
145
146impl<'a> From<&bool> for Value<'a> {
147    fn from(value: &bool) -> Self {
148        Value::Bool(*value)
149    }
150}
151
152impl<'a> From<i64> for Value<'a> {
153    fn from(value: i64) -> Self {
154        Value::I64(value)
155    }
156}
157
158impl<'a> From<&i64> for Value<'a> {
159    fn from(value: &i64) -> Self {
160        Value::I64(*value)
161    }
162}
163
164impl<'a> From<f64> for Value<'a> {
165    fn from(value: f64) -> Self {
166        Value::F64(value)
167    }
168}
169
170impl<'a> From<&f64> for Value<'a> {
171    fn from(value: &f64) -> Self {
172        Value::F64(*value)
173    }
174}