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