1use faststr::FastStr;
2use serde::ser::{Serialize, Serializer};
3use smallvec::SmallVec;
4
5use crate::key::Key;
6use crate::wide_event::WideEvent;
7
8pub enum Value<K: Key> {
14 Null,
15 Bool(bool),
16 I64(i64),
17 U64(u64),
18 F64(f64),
19 Str(FastStr),
20 StaticStr(&'static str),
21 Array(Box<SmallVec<[Value<K>; 8]>>),
22 Object(Box<WideEvent<K>>),
23}
24
25impl<K: Key> Value<K> {
26 #[inline]
28 pub(crate) fn from_object(ev: WideEvent<K>) -> Self {
29 Value::Object(Box::new(ev))
30 }
31
32 #[inline]
34 pub(crate) fn is_object(&self) -> bool {
35 matches!(self, Value::Object(_))
36 }
37}
38
39#[cfg(test)]
40impl<K: Key> Value<K> {
41 #[inline]
43 pub(crate) fn from_array(arr: SmallVec<[Value<K>; 8]>) -> Self {
44 Value::Array(Box::new(arr))
45 }
46
47 #[inline]
48 pub(crate) fn as_str(&self) -> Option<&str> {
49 match self {
50 Value::Str(s) => Some(s.as_str()),
51 Value::StaticStr(s) => Some(s),
52 _ => None,
53 }
54 }
55
56 #[inline]
58 pub(crate) fn as_array_ref(&self) -> Option<&SmallVec<[Value<K>; 8]>> {
59 match self {
60 Value::Array(arr) => Some(arr),
61 _ => None,
62 }
63 }
64
65 #[inline]
67 pub(crate) fn from_static_str(s: &'static str) -> Self {
68 Value::StaticStr(s)
69 }
70}
71
72impl<K: Key> Clone for Value<K> {
73 #[inline]
74 fn clone(&self) -> Self {
75 match self {
76 Value::Null => Value::Null,
77 Value::Bool(b) => Value::Bool(*b),
78 Value::I64(i) => Value::I64(*i),
79 Value::U64(u) => Value::U64(*u),
80 Value::F64(f) => Value::F64(*f),
81 Value::Str(s) => Value::Str(s.clone()),
82 Value::StaticStr(s) => Value::StaticStr(s),
83 Value::Array(arr) => Value::Array(arr.clone()),
84 Value::Object(obj) => Value::Object(obj.clone()),
85 }
86 }
87}
88
89impl<K: Key> std::fmt::Debug for Value<K> {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 match self {
92 Value::Null => f.write_str("Value::Null"),
93 Value::Bool(b) => f.debug_tuple("Value::Bool").field(b).finish(),
94 Value::I64(i) => f.debug_tuple("Value::I64").field(i).finish(),
95 Value::U64(u) => f.debug_tuple("Value::U64").field(u).finish(),
96 Value::F64(fl) => f.debug_tuple("Value::F64").field(fl).finish(),
97 Value::Str(s) => f.debug_tuple("Value::Str").field(s).finish(),
98 Value::StaticStr(s) => f.debug_tuple("Value::StaticStr").field(s).finish(),
99 Value::Array(arr) => f.debug_tuple("Value::Array").field(arr).finish(),
100 Value::Object(obj) => f.debug_tuple("Value::Object").field(obj).finish(),
101 }
102 }
103}
104
105impl<K: Key> Serialize for Value<K> {
106 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
107 match self {
108 Value::Null => serializer.serialize_unit(),
109 Value::Bool(b) => serializer.serialize_bool(*b),
110 Value::I64(i) => serializer.serialize_i64(*i),
111 Value::U64(u) => serializer.serialize_u64(*u),
112 Value::F64(f) => serializer.serialize_f64(*f),
113 Value::Str(s) => serializer.serialize_str(s.as_str()),
114 Value::StaticStr(s) => serializer.serialize_str(s),
115 Value::Array(arr) => arr.serialize(serializer),
116 Value::Object(obj) => obj.serialize(serializer),
117 }
118 }
119}
120
121impl<K: Key> From<bool> for Value<K> {
124 #[inline]
125 fn from(b: bool) -> Self {
126 Value::Bool(b)
127 }
128}
129
130impl<K: Key> From<i64> for Value<K> {
131 #[inline]
132 fn from(n: i64) -> Self {
133 Value::I64(n)
134 }
135}
136
137impl<K: Key> From<u64> for Value<K> {
138 #[inline]
139 fn from(n: u64) -> Self {
140 Value::U64(n)
141 }
142}
143
144impl<K: Key> From<f64> for Value<K> {
145 #[inline]
146 fn from(n: f64) -> Self {
147 Value::F64(n)
148 }
149}
150
151impl<K: Key> From<&str> for Value<K> {
152 #[inline]
153 fn from(s: &str) -> Self {
154 Value::Str(FastStr::new(s))
155 }
156}
157
158impl<K: Key> From<String> for Value<K> {
159 #[inline]
160 fn from(s: String) -> Self {
161 Value::Str(FastStr::from_string(s))
162 }
163}
164
165impl<K: Key> From<FastStr> for Value<K> {
166 #[inline]
167 fn from(s: FastStr) -> Self {
168 Value::Str(s)
169 }
170}
171
172impl<K: Key> From<()> for Value<K> {
173 #[inline]
174 fn from(_: ()) -> Self {
175 Value::Null
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use crate::key::test_support::TestKey;
183
184 #[test]
185 fn from_bool() {
186 assert!(matches!(Value::<TestKey>::from(true), Value::Bool(true)));
187 assert!(matches!(Value::<TestKey>::from(false), Value::Bool(false)));
188 }
189
190 #[test]
191 fn from_i64() {
192 let v = Value::<TestKey>::from(-42i64);
193 assert!(matches!(v, Value::I64(-42)));
194 }
195
196 #[test]
197 fn from_u64() {
198 let v = Value::<TestKey>::from(99u64);
199 assert!(matches!(v, Value::U64(99)));
200 }
201
202 #[test]
203 fn from_f64() {
204 let v = Value::<TestKey>::from(3.15f64);
205 assert!(matches!(v, Value::F64(_)));
206 }
207
208 #[test]
209 fn from_str_is_string() {
210 let v = Value::<TestKey>::from("hello");
211 assert!(matches!(v, Value::Str(_)));
212 assert_eq!(v.as_str(), Some("hello"));
213 }
214
215 #[test]
216 fn from_static_str() {
217 let v = Value::<TestKey>::from_static_str("world");
218 assert!(matches!(v, Value::StaticStr(_)));
219 assert_eq!(v.as_str(), Some("world"));
220 }
221
222 #[test]
223 fn from_owned_string_is_string() {
224 let v = Value::<TestKey>::from("world".to_string());
225 assert!(matches!(v, Value::Str(_)));
226 assert_eq!(v.as_str(), Some("world"));
227 }
228
229 #[test]
230 fn from_unit_is_null() {
231 assert!(matches!(Value::<TestKey>::from(()), Value::Null));
232 }
233
234 #[test]
235 fn serialize_null() {
236 let v = Value::<TestKey>::from(());
237 let s = sonic_rs::to_string(&v).unwrap();
238 assert_eq!(s, "null");
239 }
240
241 #[test]
242 fn serialize_scalars() {
243 assert_eq!(
244 sonic_rs::to_string(&Value::<TestKey>::from(true)).unwrap(),
245 "true"
246 );
247 assert_eq!(
248 sonic_rs::to_string(&Value::<TestKey>::from(false)).unwrap(),
249 "false"
250 );
251 assert_eq!(
252 sonic_rs::to_string(&Value::<TestKey>::from(-7i64)).unwrap(),
253 "-7"
254 );
255 assert_eq!(
256 sonic_rs::to_string(&Value::<TestKey>::from(42u64)).unwrap(),
257 "42"
258 );
259 assert_eq!(
260 sonic_rs::to_string(&Value::<TestKey>::from("hi")).unwrap(),
261 "\"hi\""
262 );
263 }
264
265 #[test]
266 fn serialize_static_str() {
267 let v = Value::<TestKey>::from_static_str("hello");
268 assert_eq!(sonic_rs::to_string(&v).unwrap(), "\"hello\"");
269 }
270
271 #[test]
272 fn serialize_array() {
273 let arr: SmallVec<[Value<TestKey>; 8]> =
274 smallvec::smallvec![Value::from(1i64), Value::from(2i64)];
275 let v = Value::<TestKey>::from_array(arr);
276 assert_eq!(sonic_rs::to_string(&v).unwrap(), "[1,2]");
277 }
278
279 #[test]
280 fn clone_works() {
281 let v = Value::<TestKey>::from("hello");
282 let v2 = v.clone();
283 assert_eq!(v2.as_str(), Some("hello"));
284 }
285
286 #[test]
287 fn clone_static_str() {
288 let v = Value::<TestKey>::from_static_str("world");
289 let v2 = v.clone();
290 assert_eq!(v2.as_str(), Some("world"));
291 }
292
293 #[test]
294 fn clone_object() {
295 let mut ev = WideEvent::<TestKey>::new();
296 ev.add(TestKey::Status, "ok");
297 let v = Value::<TestKey>::from_object(ev);
298 let v2 = v.clone();
299 assert!(matches!(v2, Value::Object(_)));
300 let json = sonic_rs::to_string(&v2).unwrap();
301 assert!(json.contains("\"status\":\"ok\""));
302 }
303}