Skip to main content

zelos_trace_types/
value.rs

1use anyhow::{Result, anyhow};
2use base64::prelude::*;
3use std::fmt;
4
5use crate::DataType;
6
7/// An enum for wrapping primitive types as generics.
8#[derive(Debug, Clone)]
9pub enum Value {
10    Int8(i8),
11    Int16(i16),
12    Int32(i32),
13    Int64(i64),
14    UInt8(u8),
15    UInt16(u16),
16    UInt32(u32),
17    UInt64(u64),
18    Float32(f32),
19    Float64(f64),
20    TimestampNs(i64),
21    Binary(Vec<u8>),
22    String(String),
23    Boolean(bool),
24}
25
26// Manually implement PartialEq for Value so we can make float NaN == NaN
27impl PartialEq for Value {
28    fn eq(&self, other: &Self) -> bool {
29        match (self, other) {
30            (Value::Int8(a), Value::Int8(b)) => a == b,
31            (Value::Int16(a), Value::Int16(b)) => a == b,
32            (Value::Int32(a), Value::Int32(b)) => a == b,
33            (Value::Int64(a), Value::Int64(b)) => a == b,
34            (Value::UInt8(a), Value::UInt8(b)) => a == b,
35            (Value::UInt16(a), Value::UInt16(b)) => a == b,
36            (Value::UInt32(a), Value::UInt32(b)) => a == b,
37            (Value::UInt64(a), Value::UInt64(b)) => a == b,
38            (Value::Float32(a), Value::Float32(b)) => a.to_bits() == b.to_bits(),
39            (Value::Float64(a), Value::Float64(b)) => a.to_bits() == b.to_bits(),
40            (Value::TimestampNs(a), Value::TimestampNs(b)) => a == b,
41            (Value::Binary(a), Value::Binary(b)) => a == b,
42            (Value::String(a), Value::String(b)) => a == b,
43            (Value::Boolean(a), Value::Boolean(b)) => a == b,
44            _ => false,
45        }
46    }
47}
48
49// Implement Eq for Value so we can iterate to build a hash map.
50impl Eq for Value {}
51
52// Implement Hash so we can use it as a key in a hash map.
53impl std::hash::Hash for Value {
54    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
55        match self {
56            Value::Int8(v) => {
57                0_i8.hash(state);
58                v.hash(state);
59            }
60            Value::Int16(v) => {
61                1_i8.hash(state);
62                v.hash(state);
63            }
64            Value::Int32(v) => {
65                2_i8.hash(state);
66                v.hash(state);
67            }
68            Value::Int64(v) => {
69                3_i8.hash(state);
70                v.hash(state);
71            }
72            Value::UInt8(v) => {
73                4_i8.hash(state);
74                v.hash(state);
75            }
76            Value::UInt16(v) => {
77                5_i8.hash(state);
78                v.hash(state);
79            }
80            Value::UInt32(v) => {
81                6_i8.hash(state);
82                v.hash(state);
83            }
84            Value::UInt64(v) => {
85                7_i8.hash(state);
86                v.hash(state);
87            }
88            Value::Float32(v) => {
89                8_i8.hash(state);
90                v.to_bits().hash(state);
91            }
92            Value::Float64(v) => {
93                9_i8.hash(state);
94                v.to_bits().hash(state);
95            }
96            Value::TimestampNs(v) => {
97                10_i8.hash(state);
98                v.hash(state);
99            }
100            Value::Binary(v) => {
101                11_i8.hash(state);
102                v.hash(state);
103            }
104            Value::String(v) => {
105                12_i8.hash(state);
106                v.hash(state);
107            }
108            Value::Boolean(v) => {
109                13_i8.hash(state);
110                v.hash(state);
111            }
112        }
113    }
114}
115
116impl fmt::Display for Value {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        match self {
119            Value::Int8(v) => write!(f, "{}", v),
120            Value::Int16(v) => write!(f, "{}", v),
121            Value::Int32(v) => write!(f, "{}", v),
122            Value::Int64(v) => write!(f, "{}", v),
123            Value::UInt8(v) => write!(f, "{}", v),
124            Value::UInt16(v) => write!(f, "{}", v),
125            Value::UInt32(v) => write!(f, "{}", v),
126            Value::UInt64(v) => write!(f, "{}", v),
127            Value::Float32(v) => write!(f, "{}", v),
128            Value::Float64(v) => write!(f, "{}", v),
129            Value::TimestampNs(v) => write!(f, "{}", v),
130            Value::Binary(items) => write!(f, "{}", BASE64_STANDARD.encode(items)),
131            Value::String(v) => write!(f, "{}", v),
132            Value::Boolean(v) => write!(f, "{}", v),
133        }
134    }
135}
136
137impl Value {
138    pub fn data_type(&self) -> DataType {
139        match self {
140            Value::Int8(_) => DataType::Int8,
141            Value::Int16(_) => DataType::Int16,
142            Value::Int32(_) => DataType::Int32,
143            Value::Int64(_) => DataType::Int64,
144            Value::UInt8(_) => DataType::UInt8,
145            Value::UInt16(_) => DataType::UInt16,
146            Value::UInt32(_) => DataType::UInt32,
147            Value::UInt64(_) => DataType::UInt64,
148            Value::Float32(_) => DataType::Float32,
149            Value::Float64(_) => DataType::Float64,
150            Value::TimestampNs(_) => DataType::TimestampNs,
151            Value::Binary(_) => DataType::Binary,
152            Value::String(_) => DataType::String,
153            Value::Boolean(_) => DataType::Boolean,
154        }
155    }
156
157    pub fn as_i8(&self) -> Option<i8> {
158        match self {
159            Value::Int8(v) => Some(*v),
160            _ => None,
161        }
162    }
163
164    pub fn as_i16(&self) -> Option<i16> {
165        match self {
166            Value::Int16(v) => Some(*v),
167            _ => None,
168        }
169    }
170
171    pub fn as_i32(&self) -> Option<i32> {
172        match self {
173            Value::Int32(v) => Some(*v),
174            _ => None,
175        }
176    }
177
178    pub fn as_i64(&self) -> Option<i64> {
179        match self {
180            Value::Int64(v) => Some(*v),
181            _ => None,
182        }
183    }
184
185    pub fn as_u8(&self) -> Option<u8> {
186        match self {
187            Value::UInt8(v) => Some(*v),
188            _ => None,
189        }
190    }
191
192    pub fn as_u16(&self) -> Option<u16> {
193        match self {
194            Value::UInt16(v) => Some(*v),
195            _ => None,
196        }
197    }
198
199    pub fn as_u32(&self) -> Option<u32> {
200        match self {
201            Value::UInt32(v) => Some(*v),
202            _ => None,
203        }
204    }
205
206    pub fn as_u64(&self) -> Option<u64> {
207        match self {
208            Value::UInt64(v) => Some(*v),
209            _ => None,
210        }
211    }
212
213    pub fn as_f32(&self) -> Option<f32> {
214        match self {
215            Value::Float32(v) => Some(*v),
216            _ => None,
217        }
218    }
219
220    pub fn as_f64(&self) -> Option<f64> {
221        match self {
222            Value::Float64(v) => Some(*v),
223            _ => None,
224        }
225    }
226
227    pub fn as_timestamp_ns(&self) -> Option<i64> {
228        match self {
229            Value::TimestampNs(v) => Some(*v),
230            _ => None,
231        }
232    }
233
234    pub fn as_binary(&self) -> Option<&Vec<u8>> {
235        match self {
236            Value::Binary(v) => Some(v),
237            _ => None,
238        }
239    }
240
241    pub fn as_str(&self) -> Option<&str> {
242        match self {
243            Value::String(v) => Some(v),
244            _ => None,
245        }
246    }
247
248    pub fn as_bool(&self) -> Option<bool> {
249        match self {
250            Value::Boolean(v) => Some(*v),
251            _ => None,
252        }
253    }
254
255    pub fn as_number(&self) -> Option<serde_json::Number> {
256        match self {
257            Value::Int8(v) => Some(serde_json::Number::from(*v)),
258            Value::Int16(v) => Some(serde_json::Number::from(*v)),
259            Value::Int32(v) => Some(serde_json::Number::from(*v)),
260            Value::Int64(v) => Some(serde_json::Number::from(*v)),
261            Value::UInt8(v) => Some(serde_json::Number::from(*v)),
262            Value::UInt16(v) => Some(serde_json::Number::from(*v)),
263            Value::UInt32(v) => Some(serde_json::Number::from(*v)),
264            Value::UInt64(v) => Some(serde_json::Number::from(*v)),
265            _ => None,
266        }
267    }
268
269    pub fn from_number_as_type(value: &serde_json::Number, data_type: &DataType) -> Option<Value> {
270        match data_type {
271            DataType::Int8 => value
272                .as_i64()
273                .and_then(|v| v.try_into().ok())
274                .map(Value::Int8),
275            DataType::Int16 => value
276                .as_i64()
277                .and_then(|v| v.try_into().ok())
278                .map(Value::Int16),
279            DataType::Int32 => value
280                .as_i64()
281                .and_then(|v| v.try_into().ok())
282                .map(Value::Int32),
283            DataType::Int64 => value.as_i64().map(Value::Int64),
284            DataType::UInt8 => value
285                .as_u64()
286                .and_then(|v| v.try_into().ok())
287                .map(Value::UInt8),
288            DataType::UInt16 => value
289                .as_u64()
290                .and_then(|v| v.try_into().ok())
291                .map(Value::UInt16),
292            DataType::UInt32 => value
293                .as_u64()
294                .and_then(|v| v.try_into().ok())
295                .map(Value::UInt32),
296            DataType::UInt64 => value.as_u64().map(Value::UInt64),
297            _ => None,
298        }
299    }
300
301    pub fn try_from_serde_json_as_type(
302        value: serde_json::Value,
303        data_type: &DataType,
304    ) -> Result<Value> {
305        match (data_type, value) {
306            (DataType::Int8, serde_json::Value::Number(value)) => {
307                let v = value
308                    .as_i64()
309                    .ok_or(anyhow!("Unable to read number as i64"))?
310                    .try_into()?;
311                Ok(Value::Int8(v))
312            }
313            (DataType::Int16, serde_json::Value::Number(value)) => {
314                let v = value
315                    .as_i64()
316                    .ok_or(anyhow!("Unable to read number as i64"))?
317                    .try_into()?;
318                Ok(Value::Int16(v))
319            }
320            (DataType::Int32, serde_json::Value::Number(value)) => {
321                let v = value
322                    .as_i64()
323                    .ok_or(anyhow!("Unable to read number as i64"))?
324                    .try_into()?;
325                Ok(Value::Int32(v))
326            }
327            (DataType::Int64, serde_json::Value::Number(value)) => {
328                let v = value
329                    .as_i64()
330                    .ok_or(anyhow!("Unable to read number as i64"))?;
331                Ok(Value::Int64(v))
332            }
333            (DataType::UInt8, serde_json::Value::Number(value)) => {
334                let v = value
335                    .as_u64()
336                    .ok_or(anyhow!("Unable to read number as i64"))?
337                    .try_into()?;
338                Ok(Value::UInt8(v))
339            }
340            (DataType::UInt16, serde_json::Value::Number(value)) => {
341                let v = value
342                    .as_u64()
343                    .ok_or(anyhow!("Unable to read number as i64"))?
344                    .try_into()?;
345                Ok(Value::UInt16(v))
346            }
347            (DataType::UInt32, serde_json::Value::Number(value)) => {
348                let v = value
349                    .as_u64()
350                    .ok_or(anyhow!("Unable to read number as u32"))?
351                    .try_into()?;
352                Ok(Value::UInt32(v))
353            }
354            (DataType::UInt64, serde_json::Value::Number(value)) => {
355                let v = value
356                    .as_u64()
357                    .ok_or(anyhow!("Unable to read number as u64"))?;
358                Ok(Value::UInt64(v))
359            }
360            (DataType::Float32, serde_json::Value::Number(value)) => {
361                let v = value
362                    .as_f64()
363                    .ok_or(anyhow!("Unable to read number as f64"))?;
364                Ok(Value::Float32(v as f32))
365            }
366            (DataType::Float64, serde_json::Value::Number(value)) => {
367                let v = value
368                    .as_f64()
369                    .ok_or(anyhow!("Unable to read number as f64"))?;
370                Ok(Value::Float64(v))
371            }
372            (DataType::TimestampNs, serde_json::Value::Number(value)) => {
373                let v = value
374                    .as_i64()
375                    .ok_or(anyhow!("Unable to read number as i64"))?;
376                Ok(Value::TimestampNs(v))
377            }
378            (DataType::String, serde_json::Value::String(value)) => Ok(Value::String(value)),
379            (DataType::Binary, serde_json::Value::String(value)) => {
380                let decoded = BASE64_STANDARD.decode(value)?;
381                Ok(Value::Binary(decoded))
382            }
383            (DataType::Boolean, serde_json::Value::Bool(value)) => Ok(Value::Boolean(value)),
384            (to_type, from_value) => Err(anyhow!(
385                "Unsupported data type conversion: {:?} to {:?}",
386                from_value,
387                to_type,
388            )),
389        }
390    }
391
392    pub fn try_to_serde_json(value: Value) -> Result<serde_json::Value> {
393        match value {
394            Value::Int8(v) => Ok(serde_json::Value::Number(v.into())),
395            Value::Int16(v) => Ok(serde_json::Value::Number(v.into())),
396            Value::Int32(v) => Ok(serde_json::Value::Number(v.into())),
397            Value::Int64(v) => Ok(serde_json::Value::Number(v.into())),
398            Value::UInt8(v) => Ok(serde_json::Value::Number(v.into())),
399            Value::UInt16(v) => Ok(serde_json::Value::Number(v.into())),
400            Value::UInt32(v) => Ok(serde_json::Value::Number(v.into())),
401            Value::UInt64(v) => Ok(serde_json::Value::Number(v.into())),
402            Value::Float32(v) => serde_json::Number::from_f64(v as f64)
403                .map(serde_json::Value::Number)
404                .ok_or(anyhow!("Unable to convert float32 to serde_json::Value")),
405            Value::Float64(v) => serde_json::Number::from_f64(v)
406                .map(serde_json::Value::Number)
407                .ok_or(anyhow!("Unable to convert float64 to serde_json::Value")),
408            Value::TimestampNs(v) => Ok(serde_json::Value::Number(v.into())),
409            Value::Binary(v) => Ok(serde_json::Value::String(BASE64_STANDARD.encode(v))),
410            Value::String(v) => Ok(serde_json::Value::String(v)),
411            Value::Boolean(v) => Ok(serde_json::Value::Bool(v)),
412        }
413    }
414}