1use faststr::FastStr;
2use serde::ser::{Serialize, Serializer};
3use smallvec::SmallVec;
4
5use crate::key::Key;
6use crate::wide_event::WideEvent;
7
8#[repr(u8)]
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum ValueTag {
12 Null = 0,
13 Bool = 1,
14 I64 = 2,
15 U64 = 3,
16 F64 = 4,
17 Str = 5, StaticStr = 6, Array = 7, Object = 8, }
22
23#[repr(C)]
28pub(crate) union ValueData<K: Key> {
29 pub(crate) b: bool,
30 pub(crate) i: i64,
31 pub(crate) u: u64,
32 pub(crate) f: f64,
33 pub(crate) s: std::mem::ManuallyDrop<FastStr>,
34 pub(crate) static_str: &'static str,
35 pub(crate) array: std::mem::ManuallyDrop<Box<SmallVec<[Value<K>; 8]>>>,
36 pub(crate) object: std::mem::ManuallyDrop<Box<WideEvent<K>>>,
37}
38
39#[repr(C)]
72pub struct Value<K: Key> {
73 tag: ValueTag,
74 _pad: [u8; 7],
75 pub(crate) data: ValueData<K>,
76}
77
78impl<K: Key> Value<K> {
79 #[inline]
81 pub(crate) fn from_object(ev: WideEvent<K>) -> Self {
82 Value { tag: ValueTag::Object, _pad: [0; 7], data: ValueData { object: std::mem::ManuallyDrop::new(Box::new(ev)) } }
83 }
84
85 #[inline]
87 #[allow(dead_code)]
88 pub(crate) fn from_array(arr: SmallVec<[Value<K>; 8]>) -> Self {
89 Value { tag: ValueTag::Array, _pad: [0; 7], data: ValueData { array: std::mem::ManuallyDrop::new(Box::new(arr)) } }
90 }
91
92 #[inline]
94 pub fn tag(&self) -> ValueTag {
95 self.tag
96 }
97
98 #[inline]
100 pub fn is_object(&self) -> bool {
101 self.tag == ValueTag::Object
102 }
103
104 #[inline]
105 pub fn as_str(&self) -> Option<&str> {
106 match self.tag {
107 ValueTag::Str => Some(unsafe { &self.data.s }.as_str()),
108 ValueTag::StaticStr => Some(unsafe { self.data.static_str }),
109 _ => None,
110 }
111 }
112
113 #[inline]
114 pub fn as_u64(&self) -> Option<u64> {
115 match self.tag {
116 ValueTag::U64 => Some(unsafe { self.data.u }),
117 _ => None,
118 }
119 }
120
121 #[inline]
122 pub fn as_i64(&self) -> Option<i64> {
123 match self.tag {
124 ValueTag::I64 => Some(unsafe { self.data.i }),
125 _ => None,
126 }
127 }
128
129 #[inline]
131 #[allow(dead_code)]
132 pub(crate) fn as_array_mut(&mut self) -> Option<&mut SmallVec<[Value<K>; 8]>> {
133 if self.tag == ValueTag::Array {
134 Some(unsafe { &mut **self.data.array })
135 } else {
136 None
137 }
138 }
139
140 #[inline]
142 #[allow(dead_code)]
143 pub(crate) fn as_array_ref(&self) -> Option<&SmallVec<[Value<K>; 8]>> {
144 if self.tag == ValueTag::Array {
145 Some(unsafe { &**self.data.array })
146 } else {
147 None
148 }
149 }
150}
151
152impl<K: Key> Clone for Value<K> {
153 fn clone(&self) -> Self {
154 let tag = self.tag;
155 let data = match tag {
156 ValueTag::Null => ValueData { b: false },
157 ValueTag::Bool => ValueData { b: unsafe { self.data.b } },
158 ValueTag::I64 => ValueData { i: unsafe { self.data.i } },
159 ValueTag::U64 => ValueData { u: unsafe { self.data.u } },
160 ValueTag::F64 => ValueData { f: unsafe { self.data.f } },
161 ValueTag::Str => ValueData { s: std::mem::ManuallyDrop::new(unsafe { (*self.data.s).clone() }) },
162 ValueTag::StaticStr => ValueData { static_str: unsafe { self.data.static_str } },
163 ValueTag::Array => ValueData { array: std::mem::ManuallyDrop::new(unsafe { (*self.data.array).clone() }) },
164 ValueTag::Object => ValueData { object: std::mem::ManuallyDrop::new(unsafe { (*self.data.object).clone() }) },
165 };
166 Value { tag, _pad: [0; 7], data }
167 }
168}
169
170impl<K: Key> std::fmt::Debug for Value<K> {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 match self.tag {
173 ValueTag::Null => f.write_str("Value::Null"),
174 ValueTag::Bool => f.debug_tuple("Value::Bool").field(&unsafe { self.data.b }).finish(),
175 ValueTag::I64 => f.debug_tuple("Value::I64").field(&unsafe { self.data.i }).finish(),
176 ValueTag::U64 => f.debug_tuple("Value::U64").field(&unsafe { self.data.u }).finish(),
177 ValueTag::F64 => f.debug_tuple("Value::F64").field(&unsafe { self.data.f }).finish(),
178 ValueTag::Str => f.debug_tuple("Value::Str").field(&unsafe { &self.data.s }).finish(),
179 ValueTag::StaticStr => f.debug_tuple("Value::StaticStr").field(&unsafe { self.data.static_str }).finish(),
180 ValueTag::Array => f.debug_tuple("Value::Array").field(&unsafe { &self.data.array }).finish(),
181 ValueTag::Object => f.debug_tuple("Value::Object").field(&unsafe { &self.data.object }).finish(),
182 }
183 }
184}
185
186impl<K: Key> Drop for Value<K> {
187 fn drop(&mut self) {
188 match self.tag {
189 ValueTag::Str => unsafe { std::ptr::drop_in_place(&mut self.data.s) },
190 ValueTag::Array => unsafe { std::ptr::drop_in_place(&mut self.data.array) },
191 ValueTag::Object => unsafe { std::ptr::drop_in_place(&mut self.data.object) },
192 _ => {}
193 }
194 }
195}
196
197impl<K: Key> Serialize for Value<K> {
198 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
199 match self.tag {
200 ValueTag::Null => serializer.serialize_unit(),
201 ValueTag::Bool => serializer.serialize_bool(unsafe { self.data.b }),
202 ValueTag::I64 => serializer.serialize_i64(unsafe { self.data.i }),
203 ValueTag::U64 => serializer.serialize_u64(unsafe { self.data.u }),
204 ValueTag::F64 => serializer.serialize_f64(unsafe { self.data.f }),
205 ValueTag::Str => serializer.serialize_str(unsafe { &self.data.s }.as_str()),
206 ValueTag::StaticStr => serializer.serialize_str(unsafe { self.data.static_str }),
207 ValueTag::Array => unsafe { &*self.data.array }.serialize(serializer),
208 ValueTag::Object => unsafe { &*self.data.object }.serialize(serializer),
209 }
210 }
211}
212
213impl<K: Key> From<bool> for Value<K> {
216 #[inline]
217 fn from(b: bool) -> Self {
218 Value { tag: ValueTag::Bool, _pad: [0; 7], data: ValueData { b } }
219 }
220}
221
222impl<K: Key> From<i64> for Value<K> {
223 #[inline]
224 fn from(n: i64) -> Self {
225 Value { tag: ValueTag::I64, _pad: [0; 7], data: ValueData { i: n } }
226 }
227}
228
229impl<K: Key> From<u64> for Value<K> {
230 #[inline]
231 fn from(n: u64) -> Self {
232 Value { tag: ValueTag::U64, _pad: [0; 7], data: ValueData { u: n } }
233 }
234}
235
236impl<K: Key> From<f64> for Value<K> {
237 #[inline]
238 fn from(n: f64) -> Self {
239 Value { tag: ValueTag::F64, _pad: [0; 7], data: ValueData { f: n } }
240 }
241}
242
243impl<K: Key> From<&str> for Value<K> {
244 #[inline]
245 fn from(s: &str) -> Self {
246 Value { tag: ValueTag::Str, _pad: [0; 7], data: ValueData { s: std::mem::ManuallyDrop::new(FastStr::new(s)) } }
247 }
248}
249
250impl<K: Key> Value<K> {
254 #[inline]
256 pub fn from_static_str(s: &'static str) -> Self {
257 Value { tag: ValueTag::StaticStr, _pad: [0; 7], data: ValueData { static_str: s } }
258 }
259}
260
261impl<K: Key> From<String> for Value<K> {
262 #[inline]
263 fn from(s: String) -> Self {
264 Value { tag: ValueTag::Str, _pad: [0; 7], data: ValueData { s: std::mem::ManuallyDrop::new(FastStr::from_string(s)) } }
265 }
266}
267
268impl<K: Key> From<FastStr> for Value<K> {
269 #[inline]
270 fn from(s: FastStr) -> Self {
271 Value { tag: ValueTag::Str, _pad: [0; 7], data: ValueData { s: std::mem::ManuallyDrop::new(s) } }
272 }
273}
274
275impl<K: Key> From<()> for Value<K> {
276 #[inline]
277 fn from(_: ()) -> Self {
278 Value { tag: ValueTag::Null, _pad: [0; 7], data: ValueData { b: false } }
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285 use crate::key::test_support::TestKey;
286
287 #[test]
288 fn from_bool() {
289 assert!(matches!(Value::<TestKey>::from(true).tag(), ValueTag::Bool));
290 assert!(unsafe { Value::<TestKey>::from(true).data.b });
291 assert!(!unsafe { Value::<TestKey>::from(false).data.b });
292 }
293
294 #[test]
295 fn from_i64() {
296 let v = Value::<TestKey>::from(-42i64);
297 assert_eq!(v.tag(), ValueTag::I64);
298 assert_eq!(unsafe { v.data.i }, -42);
299 }
300
301 #[test]
302 fn from_u64() {
303 let v = Value::<TestKey>::from(99u64);
304 assert_eq!(v.tag(), ValueTag::U64);
305 assert_eq!(unsafe { v.data.u }, 99);
306 }
307
308 #[test]
309 fn from_f64() {
310 let v = Value::<TestKey>::from(3.15f64);
311 assert_eq!(v.tag(), ValueTag::F64);
312 assert_eq!(unsafe { v.data.f }, 3.15);
313 }
314
315 #[test]
316 fn from_str_is_string() {
317 let v = Value::<TestKey>::from("hello");
318 assert_eq!(v.tag(), ValueTag::Str);
319 assert_eq!(v.as_str(), Some("hello"));
320 }
321
322 #[test]
323 fn from_static_str() {
324 let v = Value::<TestKey>::from_static_str("world");
325 assert_eq!(v.tag(), ValueTag::StaticStr);
326 assert_eq!(v.as_str(), Some("world"));
327 }
328
329 #[test]
330 fn from_owned_string_is_string() {
331 let v = Value::<TestKey>::from("world".to_string());
332 assert_eq!(v.tag(), ValueTag::Str);
333 assert_eq!(v.as_str(), Some("world"));
334 }
335
336 #[test]
337 fn from_unit_is_null() {
338 let v = Value::<TestKey>::from(());
339 assert_eq!(v.tag(), ValueTag::Null);
340 }
341
342 #[test]
343 fn serialize_null() {
344 let v = Value::<TestKey>::from(());
345 let s = sonic_rs::to_string(&v).unwrap();
346 assert_eq!(s, "null");
347 }
348
349 #[test]
350 fn serialize_scalars() {
351 assert_eq!(
352 sonic_rs::to_string(&Value::<TestKey>::from(true)).unwrap(),
353 "true"
354 );
355 assert_eq!(
356 sonic_rs::to_string(&Value::<TestKey>::from(false)).unwrap(),
357 "false"
358 );
359 assert_eq!(
360 sonic_rs::to_string(&Value::<TestKey>::from(-7i64)).unwrap(),
361 "-7"
362 );
363 assert_eq!(
364 sonic_rs::to_string(&Value::<TestKey>::from(42u64)).unwrap(),
365 "42"
366 );
367 assert_eq!(
368 sonic_rs::to_string(&Value::<TestKey>::from("hi")).unwrap(),
369 "\"hi\""
370 );
371 }
372
373 #[test]
374 fn serialize_static_str() {
375 let v = Value::<TestKey>::from_static_str("hello");
376 assert_eq!(sonic_rs::to_string(&v).unwrap(), "\"hello\"");
377 }
378
379 #[test]
380 fn serialize_array() {
381 let arr: SmallVec<[Value<TestKey>; 8]> =
382 smallvec::smallvec![Value::from(1i64), Value::from(2i64)];
383 let v = Value::<TestKey>::from_array(arr);
384 assert_eq!(sonic_rs::to_string(&v).unwrap(), "[1,2]");
385 }
386
387 #[test]
388 fn clone_works() {
389 let v = Value::<TestKey>::from("hello");
390 let v2 = v.clone();
391 assert_eq!(v2.as_str(), Some("hello"));
392 }
393
394 #[test]
395 fn clone_static_str() {
396 let v = Value::<TestKey>::from_static_str("world");
397 let v2 = v.clone();
398 assert_eq!(v2.as_str(), Some("world"));
399 }
400
401 #[test]
402 fn clone_object() {
403 let mut ev = WideEvent::<TestKey>::new();
404 ev.add(TestKey::Status, "ok");
405 let v = Value::<TestKey>::from_object(ev);
406 let v2 = v.clone();
407 assert_eq!(v2.tag(), ValueTag::Object);
408 let json = sonic_rs::to_string(&v2).unwrap();
409 assert!(json.contains("\"status\":\"ok\""));
410 }
411}