veecle_telemetry/
value.rs

1//! Key-value attribute types for telemetry data.
2//!
3//! This module defines the types used to represent attributes in telemetry data.
4//! Attributes are key-value pairs that provide additional context for spans,
5//! events, and log messages.
6//!
7//! # Value Types
8//!
9//! The [`Value`] enum supports common data types:
10//! - **String**: Text values (adapted to platform string type)
11//! - **Bool**: Boolean values (true/false)
12//! - **I64**: 64-bit signed integers
13//! - **F64**: 64-bit floating-point numbers
14//!
15//! # Examples
16//!
17//! ```rust
18//! use veecle_telemetry::types::StringType;
19//! use veecle_telemetry::{KeyValue, Value};
20//!
21//! // Create key-value pairs
22//! let user_id = KeyValue::new("user_id", 123);
23//! let username = KeyValue::new("username", "alice");
24//! let is_admin = KeyValue::new("is_admin", true);
25//! let score = KeyValue::new("score", 95.5);
26//!
27//! // Values can be created from various types
28//! let string_value = Value::String("hello".into());
29//! let int_value = Value::I64(42);
30//! let bool_value = Value::Bool(true);
31//! let float_value = Value::F64(3.14);
32//! ```
33
34use serde::{Deserialize, Serialize};
35
36#[cfg(feature = "alloc")]
37use crate::to_static::ToStatic;
38use crate::types::StringType;
39
40/// A key-value attribute pair used in telemetry data.
41///
42/// Key-value pairs provide additional context for spans, events, and log messages.
43/// The key is typically a string identifier, and the value can be one of several
44/// supported data types.
45///
46/// # Examples
47///
48/// ```rust
49/// use veecle_telemetry::types::StringType;
50/// use veecle_telemetry::{KeyValue, Value};
51///
52/// // Create attributes with different value types
53/// let user_id = KeyValue::new("user_id", 123);
54/// let username = KeyValue::new("username", "alice");
55/// let is_active = KeyValue::new("is_active", true);
56/// let score = KeyValue::new("score", 95.5);
57/// ```
58#[derive(Clone, Debug, Serialize, Deserialize)]
59pub struct KeyValue<'a> {
60    /// The attribute key (name)
61    #[serde(borrow)]
62    pub key: StringType<'a>,
63    /// The attribute value
64    #[serde(borrow)]
65    pub value: Value<'a>,
66}
67
68impl<'a> KeyValue<'a> {
69    /// Creates a new key-value attribute pair.
70    ///
71    /// # Arguments
72    ///
73    /// * `key` - The attribute key (name)
74    /// * `value` - The attribute value
75    ///
76    /// # Examples
77    ///
78    /// ```rust
79    /// use veecle_telemetry::KeyValue;
80    ///
81    /// let user_id = KeyValue::new("user_id", 123);
82    /// let username = KeyValue::new("username", "alice");
83    /// ```
84    pub fn new<K, V>(key: K, value: V) -> Self
85    where
86        K: Into<StringType<'a>>,
87        V: Into<Value<'a>>,
88    {
89        Self {
90            key: key.into(),
91            value: value.into(),
92        }
93    }
94}
95
96impl core::fmt::Display for KeyValue<'_> {
97    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98        write!(f, "{}: {}", self.key, self.value)
99    }
100}
101
102#[cfg(feature = "alloc")]
103impl ToStatic for KeyValue<'_> {
104    type Static = KeyValue<'static>;
105
106    fn to_static(&self) -> Self::Static {
107        KeyValue {
108            key: self.key.clone().into_owned().into(),
109            value: self.value.to_static(),
110        }
111    }
112}
113
114/// A value that can be stored in a telemetry attribute.
115///
116/// This enum represents the different types of values that can be associated
117///
118/// # Examples
119///
120/// ```rust
121/// use veecle_telemetry::Value;
122///
123/// // Create values of different types
124/// let text = Value::String("hello world".into());
125/// let number = Value::I64(42);
126/// let flag = Value::Bool(true);
127/// let rating = Value::F64(4.5);
128/// ```
129#[derive(Clone, Debug, Serialize, Deserialize)]
130pub enum Value<'a> {
131    /// A string value (adapted to platform string type)
132    String(#[serde(borrow)] StringType<'a>),
133    /// A boolean value
134    Bool(bool),
135    /// A 64-bit signed integer
136    I64(i64),
137    /// A 64-bit floating-point number
138    F64(f64),
139}
140
141#[cfg(feature = "alloc")]
142impl ToStatic for Value<'_> {
143    type Static = Value<'static>;
144
145    fn to_static(&self) -> Self::Static {
146        match self {
147            Value::String(s) => Value::String(s.clone().into_owned().into()),
148            Value::Bool(b) => Value::Bool(*b),
149            Value::I64(i) => Value::I64(*i),
150            Value::F64(f) => Value::F64(*f),
151        }
152    }
153}
154
155impl<'a> core::fmt::Display for Value<'a> {
156    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
157        match self {
158            // For strings, debug print so they will get delimiters, since we are explicitly
159            // representing strings rather than directly human-targeted text, and they will be used
160            // in situations where knowing where the string ends is important.
161            Value::String(value) => write!(f, "{value:?}"),
162            Value::Bool(value) => write!(f, "{value}"),
163            Value::I64(value) => write!(f, "{value}"),
164            Value::F64(value) => write!(f, "{value}"),
165        }
166    }
167}
168
169#[cfg(feature = "alloc")]
170impl<'a> From<alloc::borrow::Cow<'a, str>> for Value<'a> {
171    fn from(value: alloc::borrow::Cow<'a, str>) -> Self {
172        Value::String(value)
173    }
174}
175
176#[cfg(feature = "alloc")]
177impl<'a> From<alloc::string::String> for Value<'a> {
178    fn from(value: alloc::string::String) -> Self {
179        Value::String(value.into())
180    }
181}
182
183#[cfg(feature = "alloc")]
184impl<'a> From<&'a alloc::string::String> for Value<'a> {
185    fn from(value: &'a alloc::string::String) -> Self {
186        Value::String(value.into())
187    }
188}
189
190impl<'a> From<&'a str> for Value<'a> {
191    fn from(value: &'a str) -> Self {
192        #[cfg(feature = "alloc")]
193        {
194            Value::String(alloc::borrow::Cow::Borrowed(value))
195        }
196        #[cfg(not(feature = "alloc"))]
197        {
198            Value::String(value)
199        }
200    }
201}
202
203impl From<bool> for Value<'_> {
204    fn from(value: bool) -> Self {
205        Value::Bool(value)
206    }
207}
208
209impl From<i64> for Value<'_> {
210    fn from(value: i64) -> Self {
211        Value::I64(value)
212    }
213}
214
215impl From<f64> for Value<'_> {
216    fn from(value: f64) -> Self {
217        Value::F64(value)
218    }
219}