relay_protocol/
value.rs

1use std::collections::BTreeMap;
2use std::fmt::Debug;
3use std::{fmt, str};
4
5use serde::de::{Deserialize, MapAccess, SeqAccess, Visitor};
6use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
7use uuid::Uuid;
8
9use crate::FiniteF64;
10use crate::annotated::Annotated;
11use crate::meta::Meta;
12
13/// Alias for typed arrays.
14pub type Array<T> = Vec<Annotated<T>>;
15
16/// Alias for maps.
17pub type Map<K, T> = BTreeMap<K, T>;
18
19/// Alias for typed objects.
20pub type Object<T> = Map<String, Annotated<T>>;
21
22/// Represents a boxed value.
23#[derive(Debug, Clone, PartialEq)]
24pub enum Value {
25    /// A boolean value.
26    Bool(bool),
27    /// A signed integer value.
28    I64(i64),
29    /// An unsigned integer value.
30    U64(u64),
31    /// A floating point value.
32    F64(f64),
33    /// A string value.
34    String(String),
35    /// An array of annotated values.
36    Array(Array<Value>),
37    /// A mapping of strings to annotated values.
38    Object(Object<Value>),
39}
40
41/// Helper type that renders out a description of the value.
42pub struct ValueDescription<'a>(&'a Value);
43
44impl fmt::Display for ValueDescription<'_> {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        match *self.0 {
47            Value::Bool(true) => f.pad("true"),
48            Value::Bool(false) => f.pad("false"),
49            Value::I64(val) => write!(f, "integer {val}"),
50            Value::U64(val) => write!(f, "integer {val}"),
51            Value::F64(val) => write!(f, "float {val}"),
52            Value::String(ref val) => f.pad(val),
53            Value::Array(_) => f.pad("an array"),
54            Value::Object(_) => f.pad("an object"),
55        }
56    }
57}
58
59impl Value {
60    /// Returns a formattable that gives a helper description of the value.
61    pub fn describe(&self) -> ValueDescription<'_> {
62        ValueDescription(self)
63    }
64
65    /// Returns the string if this value is a string, otherwise `None`.
66    pub fn as_str(&self) -> Option<&str> {
67        match self {
68            Value::String(string) => Some(string.as_str()),
69            _ => None,
70        }
71    }
72
73    /// Returns the string if this value is a string, otherwise `None`.
74    pub fn into_string(self) -> Option<String> {
75        match self {
76            Value::String(string) => Some(string),
77            _ => None,
78        }
79    }
80
81    /// Returns a f64 if the value can be converted to it, otherwise `None`.
82    pub fn as_f64(&self) -> Option<f64> {
83        match self {
84            Value::F64(f) => Some(*f),
85            Value::I64(i) => Some(*i as f64),
86            Value::U64(u) => Some(*u as f64),
87            _ => None,
88        }
89    }
90
91    /// Constructs a `Value` from a `serde_json::Value` object.
92    fn from_json(value: serde_json::Value) -> Option<Self> {
93        Some(match value {
94            serde_json::Value::Null => return None,
95            serde_json::Value::Bool(value) => Value::Bool(value),
96            serde_json::Value::Number(num) => {
97                if let Some(val) = num.as_i64() {
98                    Value::I64(val)
99                } else if let Some(val) = num.as_u64() {
100                    Value::U64(val)
101                } else if let Some(val) = num.as_f64() {
102                    Value::F64(val)
103                } else {
104                    // NB: Without the "arbitrary_precision" feature, serde_json's number will
105                    // always be one of the above.
106                    unreachable!()
107                }
108            }
109            serde_json::Value::String(val) => Value::String(val),
110            serde_json::Value::Array(items) => {
111                Value::Array(items.into_iter().map(Annotated::<Value>::from).collect())
112            }
113            serde_json::Value::Object(items) => Value::Object(
114                items
115                    .into_iter()
116                    .map(|(k, v)| (k, Annotated::<Value>::from(v)))
117                    .collect(),
118            ),
119        })
120    }
121}
122
123impl TryFrom<&Value> for String {
124    type Error = ();
125
126    fn try_from(value: &Value) -> Result<Self, Self::Error> {
127        Ok(match value {
128            Value::Bool(v) => v.to_string(),
129            Value::I64(v) => v.to_string(),
130            Value::U64(v) => v.to_string(),
131            Value::F64(v) => v.to_string(),
132            Value::String(v) => v.to_string(),
133            _ => return Err(()),
134        })
135    }
136}
137
138impl Serialize for Value {
139    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
140    where
141        S: Serializer,
142    {
143        match *self {
144            Value::Bool(val) => serializer.serialize_bool(val),
145            Value::I64(val) => serializer.serialize_i64(val),
146            Value::U64(val) => serializer.serialize_u64(val),
147            Value::F64(val) => serializer.serialize_f64(val),
148            Value::String(ref val) => serializer.serialize_str(val),
149            Value::Array(ref items) => {
150                let mut seq_ser = serializer.serialize_seq(Some(items.len()))?;
151                for item in items {
152                    match item {
153                        Annotated(Some(val), _) => seq_ser.serialize_element(val)?,
154                        Annotated(None, _) => seq_ser.serialize_element(&())?,
155                    }
156                }
157                seq_ser.end()
158            }
159            Value::Object(ref items) => {
160                let mut map_ser = serializer.serialize_map(Some(items.len()))?;
161                for (key, value) in items {
162                    map_ser.serialize_key(key)?;
163                    match value {
164                        Annotated(Some(val), _) => map_ser.serialize_value(val)?,
165                        Annotated(None, _) => map_ser.serialize_value(&())?,
166                    }
167                }
168                map_ser.end()
169            }
170        }
171    }
172}
173
174impl From<serde_json::Value> for Annotated<Value> {
175    fn from(value: serde_json::Value) -> Annotated<Value> {
176        Annotated::from(Value::from_json(value))
177    }
178}
179
180impl From<Value> for serde_json::Value {
181    fn from(value: Value) -> serde_json::Value {
182        match value {
183            Value::Bool(value) => serde_json::Value::Bool(value),
184            Value::I64(value) => serde_json::Value::Number(value.into()),
185            Value::U64(value) => serde_json::Value::Number(value.into()),
186            Value::F64(value) => serde_json::Number::from_f64(value)
187                .map(serde_json::Value::Number)
188                .unwrap_or(serde_json::Value::Null),
189            Value::String(val) => serde_json::Value::String(val),
190            Value::Array(items) => {
191                serde_json::Value::Array(items.into_iter().map(serde_json::Value::from).collect())
192            }
193            Value::Object(items) => serde_json::Value::Object(
194                items
195                    .into_iter()
196                    .map(|(k, v)| (k, serde_json::Value::from(v)))
197                    .collect(),
198            ),
199        }
200    }
201}
202
203impl From<Annotated<Value>> for serde_json::Value {
204    fn from(value: Annotated<Value>) -> serde_json::Value {
205        value
206            .0
207            .map(serde_json::Value::from)
208            .unwrap_or(serde_json::Value::Null)
209    }
210}
211
212impl From<bool> for Value {
213    fn from(value: bool) -> Self {
214        Value::Bool(value)
215    }
216}
217
218impl From<i64> for Value {
219    fn from(value: i64) -> Self {
220        Value::I64(value)
221    }
222}
223
224impl From<u64> for Value {
225    fn from(value: u64) -> Self {
226        Value::U64(value)
227    }
228}
229
230impl From<f64> for Value {
231    fn from(value: f64) -> Self {
232        Value::F64(value)
233    }
234}
235
236impl<'a> From<&'a str> for Value {
237    fn from(value: &'a str) -> Self {
238        Value::String(value.to_owned())
239    }
240}
241
242impl From<String> for Value {
243    fn from(value: String) -> Self {
244        Value::String(value)
245    }
246}
247
248impl From<Array<Value>> for Value {
249    fn from(value: Array<Value>) -> Self {
250        Value::Array(value)
251    }
252}
253
254impl From<Object<Value>> for Value {
255    fn from(value: Object<Value>) -> Self {
256        Value::Object(value)
257    }
258}
259
260impl<'de> Deserialize<'de> for Value {
261    #[inline]
262    fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
263    where
264        D: serde::Deserializer<'de>,
265    {
266        struct ValueVisitor;
267
268        impl<'de> Visitor<'de> for ValueVisitor {
269            type Value = Value;
270
271            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
272                formatter.write_str("any valid JSON value")
273            }
274
275            #[inline]
276            fn visit_bool<E>(self, value: bool) -> Result<Value, E> {
277                Ok(Value::Bool(value))
278            }
279
280            #[inline]
281            fn visit_i64<E>(self, value: i64) -> Result<Value, E> {
282                Ok(Value::I64(value))
283            }
284
285            #[inline]
286            fn visit_u64<E>(self, value: u64) -> Result<Value, E> {
287                Ok(value
288                    .try_into()
289                    .map(Value::I64)
290                    .unwrap_or(Value::U64(value)))
291            }
292
293            #[inline]
294            fn visit_f64<E>(self, value: f64) -> Result<Value, E> {
295                Ok(Value::F64(value))
296            }
297
298            #[inline]
299            fn visit_str<E>(self, value: &str) -> Result<Value, E>
300            where
301                E: serde::de::Error,
302            {
303                self.visit_string(String::from(value))
304            }
305
306            #[inline]
307            fn visit_string<E>(self, value: String) -> Result<Value, E> {
308                Ok(Value::String(value))
309            }
310
311            #[inline]
312            fn visit_some<D>(self, deserializer: D) -> Result<Value, D::Error>
313            where
314                D: serde::Deserializer<'de>,
315            {
316                Deserialize::deserialize(deserializer)
317            }
318
319            #[inline]
320            fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error>
321            where
322                V: SeqAccess<'de>,
323            {
324                let mut vec = Vec::new();
325                while let Some(elem) = visitor.next_element()? {
326                    vec.push(Annotated(elem, Meta::default()));
327                }
328                Ok(Value::Array(vec))
329            }
330
331            fn visit_map<V>(self, mut visitor: V) -> Result<Value, V::Error>
332            where
333                V: MapAccess<'de>,
334            {
335                let mut values = Map::new();
336                while let Some((key, value)) = visitor.next_entry()? {
337                    values.insert(key, Annotated(value, Meta::default()));
338                }
339                Ok(Value::Object(values))
340            }
341        }
342
343        deserializer.deserialize_any(ValueVisitor)
344    }
345}
346
347/// Convert `T` into a `Value`.
348pub fn to_value<T>(value: &T) -> Result<Option<Value>, serde_json::Error>
349where
350    T: Serialize,
351{
352    serde_json::to_value(value).map(Value::from_json)
353}
354
355/// Borrowed version of [`Array`].
356#[derive(Debug, Clone, Copy)]
357pub struct Arr<'a> {
358    _phantom: std::marker::PhantomData<&'a ()>,
359}
360
361/// Borrowed version of [`Object`].
362#[derive(Debug, Clone, Copy)]
363pub struct Obj<'a> {
364    _phantom: std::marker::PhantomData<&'a ()>,
365}
366
367/// Borrowed version of a "hex ID", like a span ID, UUID,
368/// &c, represented by a byte slice.
369#[derive(Debug, Clone, Copy, PartialEq, Eq)]
370pub struct HexId<'a>(pub &'a [u8]);
371
372impl HexId<'_> {
373    /// Checks whether the given string is a valid hex encoding
374    /// of `self`.
375    pub fn match_str(&self, other: &str) -> bool {
376        if other.len() != 2 * self.0.len() {
377            return false;
378        }
379
380        let sx = (0..)
381            .step_by(2)
382            .map_while(|r| other.get(r..r + 2))
383            .map(|x| u8::from_str_radix(x, 16).ok());
384
385        self.0.iter().copied().map(Some).eq(sx)
386    }
387}
388
389/// Borrowed version of [`Value`].
390#[derive(Debug, Clone, Copy)]
391pub enum Val<'a> {
392    /// A boolean value.
393    Bool(bool),
394    /// A signed integer value.
395    I64(i64),
396    /// An unsigned integer value.
397    U64(u64),
398    /// A floating point value.
399    F64(f64),
400    /// A string value.
401    String(&'a str),
402    /// A hexadecimal ID (UUID, span ID, &c).
403    HexId(HexId<'a>),
404    /// An array of annotated values.
405    Array(Arr<'a>),
406    /// A mapping of strings to annotated values.
407    Object(Obj<'a>),
408}
409
410impl<'a> Val<'a> {
411    /// Returns the value if it is a boolean, otherwise `None`.
412    pub fn as_bool(&self) -> Option<bool> {
413        match self {
414            Self::Bool(value) => Some(*value),
415            _ => None,
416        }
417    }
418
419    /// Represents the value as `f64` if possible. Returns `None` otherwise.
420    pub fn as_i64(&self) -> Option<i64> {
421        match self {
422            Self::I64(value) => Some(*value),
423            Self::U64(value) => (*value).try_into().ok(),
424            _ => None,
425        }
426    }
427
428    /// Represents the value as `f64` if possible. Returns `None` otherwise.
429    pub fn as_u64(&self) -> Option<u64> {
430        match self {
431            Self::I64(value) => (*value).try_into().ok(),
432            Self::U64(value) => Some(*value),
433            _ => None,
434        }
435    }
436
437    /// Represents the value as `f64` if possible. Returns `None` otherwise.
438    pub fn as_f64(&self) -> Option<f64> {
439        match self {
440            Self::I64(value) => Some(*value as f64),
441            Self::U64(value) => Some(*value as f64),
442            Self::F64(value) => Some(*value),
443            _ => None,
444        }
445    }
446
447    /// Returns the string if this value is a string, otherwise `None`.
448    pub fn as_str(&self) -> Option<&'a str> {
449        match self {
450            Self::String(value) => Some(value),
451
452            _ => None,
453        }
454    }
455
456    /// Returns the ID if this value is a hex ID, otherwise `None`.
457    pub fn as_hex_id(&self) -> Option<HexId<'_>> {
458        match self {
459            Self::HexId(value) => Some(*value),
460
461            _ => None,
462        }
463    }
464}
465
466impl From<bool> for Val<'_> {
467    fn from(value: bool) -> Self {
468        Self::Bool(value)
469    }
470}
471
472impl From<i64> for Val<'_> {
473    fn from(value: i64) -> Self {
474        Self::I64(value)
475    }
476}
477
478impl From<u64> for Val<'_> {
479    fn from(value: u64) -> Self {
480        Self::U64(value)
481    }
482}
483
484impl From<f64> for Val<'_> {
485    fn from(value: f64) -> Self {
486        Self::F64(value)
487    }
488}
489
490impl From<FiniteF64> for Val<'_> {
491    fn from(value: FiniteF64) -> Self {
492        Self::F64(value.to_f64())
493    }
494}
495
496impl<'a> From<&'a str> for Val<'a> {
497    fn from(value: &'a str) -> Self {
498        Self::String(value)
499    }
500}
501
502impl<'a> From<&'a Uuid> for Val<'a> {
503    fn from(value: &'a Uuid) -> Self {
504        Self::HexId(HexId(value.as_bytes()))
505    }
506}
507
508impl<'a, T> From<&'a T> for Val<'a>
509where
510    Val<'a>: From<T>,
511    T: Copy,
512{
513    fn from(value: &'a T) -> Self {
514        (*value).into()
515    }
516}
517
518impl<'a> From<&'a Value> for Val<'a> {
519    fn from(value: &'a Value) -> Self {
520        match value {
521            Value::Bool(value) => Self::Bool(*value),
522            Value::I64(value) => Self::I64(*value),
523            Value::U64(value) => Self::U64(*value),
524            Value::F64(value) => Self::F64(*value),
525            Value::String(value) => Self::String(value),
526            Value::Array(_) => Self::Array(Arr {
527                _phantom: Default::default(),
528            }),
529            Value::Object(_) => Self::Object(Obj {
530                _phantom: Default::default(),
531            }),
532        }
533    }
534}
535
536impl PartialEq for Val<'_> {
537    fn eq(&self, other: &Self) -> bool {
538        match (self, other) {
539            (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
540            (Self::I64(l0), Self::I64(r0)) => l0 == r0,
541            (Self::I64(l0), Self::U64(r0)) => Ok(*l0) == (*r0).try_into(),
542            (Self::U64(l0), Self::U64(r0)) => l0 == r0,
543            (Self::U64(l0), Self::I64(r0)) => Ok(*l0) == (*r0).try_into(),
544            (Self::F64(l0), Self::F64(r0)) => l0 == r0,
545            (Self::String(l0), Self::String(r0)) => l0 == r0,
546            (Self::HexId(l0), Self::HexId(r0)) => l0 == r0,
547            (Self::Array(_), Self::Array(_)) => false,
548            (Self::Object(_), Self::Object(_)) => false,
549            _ => false,
550        }
551    }
552}
553
554#[cfg(test)]
555mod tests {
556    use super::*;
557
558    #[test]
559    fn test_unsigned_signed() {
560        let v: Value = serde_json::from_str("9223372036854775816").unwrap();
561        assert_eq!(v, Value::U64(9223372036854775816));
562
563        let v: Value = serde_json::from_str("123").unwrap();
564        assert_eq!(v, Value::I64(123));
565    }
566
567    #[test]
568    fn test_hex_id_comparison() {
569        let id = HexId(&[0xde, 0xad, 0xbe, 0xef]);
570        assert!(id.match_str("deadbeef"));
571        // Matching is case insensitive
572        assert!(id.match_str("DEADBEEF"));
573        // Values don't match
574        assert!(!id.match_str("deedbeef"));
575        // Too short
576        assert!(!id.match_str("deadbee"));
577        // Too long
578        assert!(!id.match_str("deadbeeff"));
579        // Not a valid hex string at all
580        assert!(!id.match_str("deadbeer"));
581    }
582}