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