Skip to main content

wide_log/
value.rs

1use faststr::FastStr;
2use serde::ser::{Serialize, Serializer};
3use smallvec::SmallVec;
4
5use crate::key::Key;
6use crate::wide_event::WideEvent;
7
8/// A JSON value stored in a wide event.
9///
10/// This enum is generic over the key type `K` because `Object` and `Array`
11/// variants can contain nested [`WideEvent`]s that are parameterized by `K`.
12///
13/// # Conversions
14///
15/// All primitive types implement `Into<Value<K>>`:
16///
17/// - `bool` → [`Value::Bool`]
18/// - `i64` → [`Value::I64`]
19/// - `u64` → [`Value::U64`]
20/// - `f64` → [`Value::F64`]
21/// - `&str`, `String`, `FastStr` → [`Value::String`]
22/// - `()` → [`Value::Null`]
23///
24/// The `wl_set!` and `wl_null!` macros use these conversions transparently.
25///
26/// [`WideEvent`]: crate::WideEvent
27#[derive(Debug, Clone)]
28pub enum Value<K: Key> {
29    /// JSON `null`.
30    Null,
31    /// A boolean value.
32    Bool(bool),
33    /// A signed 64-bit integer.
34    I64(i64),
35    /// An unsigned 64-bit integer.
36    U64(u64),
37    /// A 64-bit floating-point value.
38    F64(f64),
39    /// A string value, stored with small-string optimization via `FastStr`.
40    String(FastStr),
41    /// A JSON array of values.
42    Array(SmallVec<[Box<Value<K>>; 8]>),
43    /// A nested JSON object (a boxed [`WideEvent`]).
44    ///
45    /// [`WideEvent`]: crate::WideEvent
46    Object(Box<WideEvent<K>>),
47}
48
49impl<K: Key> Serialize for Value<K> {
50    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
51        match self {
52            Value::Null => serializer.serialize_unit(),
53            Value::Bool(b) => serializer.serialize_bool(*b),
54            Value::I64(n) => serializer.serialize_i64(*n),
55            Value::U64(n) => serializer.serialize_u64(*n),
56            Value::F64(n) => serializer.serialize_f64(*n),
57            Value::String(s) => serializer.serialize_str(s.as_str()),
58            Value::Array(arr) => arr.serialize(serializer),
59            Value::Object(obj) => obj.serialize(serializer),
60        }
61    }
62}
63
64impl<K: Key> From<bool> for Value<K> {
65    #[inline]
66    fn from(b: bool) -> Self {
67        Value::Bool(b)
68    }
69}
70
71impl<K: Key> From<i64> for Value<K> {
72    #[inline]
73    fn from(n: i64) -> Self {
74        Value::I64(n)
75    }
76}
77
78impl<K: Key> From<u64> for Value<K> {
79    #[inline]
80    fn from(n: u64) -> Self {
81        Value::U64(n)
82    }
83}
84
85impl<K: Key> From<f64> for Value<K> {
86    #[inline]
87    fn from(n: f64) -> Self {
88        Value::F64(n)
89    }
90}
91
92impl<K: Key> From<&str> for Value<K> {
93    #[inline]
94    fn from(s: &str) -> Self {
95        Value::String(FastStr::new(s))
96    }
97}
98
99impl<K: Key> From<String> for Value<K> {
100    #[inline]
101    fn from(s: String) -> Self {
102        Value::String(FastStr::new(&s))
103    }
104}
105
106impl<K: Key> From<FastStr> for Value<K> {
107    #[inline]
108    fn from(s: FastStr) -> Self {
109        Value::String(s)
110    }
111}
112
113impl<K: Key> From<()> for Value<K> {
114    #[inline]
115    fn from(_: ()) -> Self {
116        Value::Null
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use crate::key::test_support::TestKey;
124
125    #[test]
126    fn from_bool() {
127        assert!(matches!(Value::<TestKey>::from(true), Value::Bool(true)));
128        assert!(matches!(Value::<TestKey>::from(false), Value::Bool(false)));
129    }
130
131    #[test]
132    fn from_i64() {
133        assert!(matches!(Value::<TestKey>::from(-42i64), Value::I64(-42)));
134    }
135
136    #[test]
137    fn from_u64() {
138        assert!(matches!(Value::<TestKey>::from(99u64), Value::U64(99)));
139    }
140
141    #[test]
142    fn from_f64() {
143        assert!(matches!(Value::<TestKey>::from(3.15f64), Value::F64(_)));
144    }
145
146    #[test]
147    fn from_str_is_string() {
148        assert!(matches!(Value::<TestKey>::from("hello"), Value::String(_)));
149    }
150
151    #[test]
152    fn from_owned_string_is_string() {
153        assert!(matches!(
154            Value::<TestKey>::from("world".to_string()),
155            Value::String(_)
156        ));
157    }
158
159    #[test]
160    fn from_unit_is_null() {
161        assert!(matches!(Value::<TestKey>::from(()), Value::Null));
162    }
163
164    #[test]
165    fn serialize_null() {
166        let v = Value::<TestKey>::from(());
167        let s = sonic_rs::to_string(&v).unwrap();
168        assert_eq!(s, "null");
169    }
170
171    #[test]
172    fn serialize_scalars() {
173        assert_eq!(
174            sonic_rs::to_string(&Value::<TestKey>::from(true)).unwrap(),
175            "true"
176        );
177        assert_eq!(
178            sonic_rs::to_string(&Value::<TestKey>::from(false)).unwrap(),
179            "false"
180        );
181        assert_eq!(
182            sonic_rs::to_string(&Value::<TestKey>::from(-7i64)).unwrap(),
183            "-7"
184        );
185        assert_eq!(
186            sonic_rs::to_string(&Value::<TestKey>::from(42u64)).unwrap(),
187            "42"
188        );
189        assert_eq!(
190            sonic_rs::to_string(&Value::<TestKey>::from("hi")).unwrap(),
191            "\"hi\""
192        );
193    }
194
195    #[test]
196    fn serialize_array() {
197        let arr: SmallVec<[Box<Value<TestKey>>; 8]> =
198            smallvec::smallvec![Box::new(Value::from(1i64)), Box::new(Value::from(2i64)),];
199        let v = Value::<TestKey>::Array(arr);
200        assert_eq!(sonic_rs::to_string(&v).unwrap(), "[1,2]");
201    }
202}