Skip to main content

relay_protocol/
value.rs

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