Skip to main content

jsonld_expandable_core/
value.rs

1//! Backend-agnostic JSON value abstraction.
2
3use std::collections::{BTreeMap, HashMap};
4
5/// Minimal vocabulary for any JSON value type the derive can construct.
6///
7/// Implement this once per backend value type. The derive's generated code
8/// never names a concrete value type; consumers select one at the call site.
9///
10/// ```ignore
11/// let v: serde_json::Value = thing.expand();      // inferred
12/// let v = thing.expand::<jstrict::Value>();        // turbofish
13/// ```
14pub trait JsonValue: Sized {
15    /// Builds the null value.
16    fn null() -> Self;
17    /// Builds a boolean value.
18    fn bool(b: bool) -> Self;
19    /// Builds a signed integer value.
20    fn integer(n: i64) -> Self;
21    /// Builds an unsigned integer value.
22    fn unsigned(n: u64) -> Self;
23    /// Non-finite (`NaN`, `±Infinity`) values become [`Self::null`] — JSON has
24    /// no representation for them.
25    fn float(n: f64) -> Self;
26    /// Builds a string value from a slice.
27    fn string(s: &str) -> Self;
28    /// Builds a string value from an owned string.
29    #[must_use]
30    fn from_string(s: String) -> Self {
31        Self::string(&s)
32    }
33    /// Builds an array from the given items.
34    fn array<I: IntoIterator<Item = Self>>(items: I) -> Self;
35    /// Builds an object from the given entries.
36    fn object<I: IntoIterator<Item = (String, Self)>>(entries: I) -> Self;
37    /// Destructure an object value back into its entries. Returns `None` for
38    /// non-object variants. Used by `flatten` to merge a sub-fragment into its
39    /// parent.
40    fn into_object_entries(self) -> Option<Vec<(String, Self)>>;
41}
42
43/// Convert a leaf field value to the chosen `JsonValue` backend.
44///
45/// Generated code calls this for fields that should land in a `{"@value": ...}`
46/// object (i.e. anything not marked `nested` / `coerce` / `container`).
47pub trait ToJsonValue<V: JsonValue> {
48    /// Converts this value into the chosen JSON backend `V`.
49    fn to_json_value(&self) -> V;
50}
51
52macro_rules! impl_int {
53    ($($t:ty)*) => {$(
54        impl<V: JsonValue> ToJsonValue<V> for $t {
55            #[inline]
56            fn to_json_value(&self) -> V { V::integer(i64::from(*self)) }
57        }
58    )*};
59}
60impl_int!(i8 i16 i32 i64);
61
62macro_rules! impl_uint_fits {
63    ($($t:ty)*) => {$(
64        impl<V: JsonValue> ToJsonValue<V> for $t {
65            #[inline]
66            fn to_json_value(&self) -> V { V::unsigned(u64::from(*self)) }
67        }
68    )*};
69}
70impl_uint_fits!(u8 u16 u32 u64);
71
72impl<V: JsonValue> ToJsonValue<V> for usize {
73    #[inline]
74    fn to_json_value(&self) -> V {
75        V::unsigned(*self as u64)
76    }
77}
78
79impl<V: JsonValue> ToJsonValue<V> for isize {
80    #[inline]
81    fn to_json_value(&self) -> V {
82        V::integer(*self as i64)
83    }
84}
85
86impl<V: JsonValue> ToJsonValue<V> for f32 {
87    #[inline]
88    fn to_json_value(&self) -> V {
89        V::float(f64::from(*self))
90    }
91}
92
93impl<V: JsonValue> ToJsonValue<V> for f64 {
94    #[inline]
95    fn to_json_value(&self) -> V {
96        V::float(*self)
97    }
98}
99
100impl<V: JsonValue> ToJsonValue<V> for bool {
101    #[inline]
102    fn to_json_value(&self) -> V {
103        V::bool(*self)
104    }
105}
106
107impl<V: JsonValue> ToJsonValue<V> for str {
108    #[inline]
109    fn to_json_value(&self) -> V {
110        V::string(self)
111    }
112}
113
114impl<V: JsonValue> ToJsonValue<V> for String {
115    #[inline]
116    fn to_json_value(&self) -> V {
117        V::string(self.as_str())
118    }
119}
120
121impl<V: JsonValue, T: ToJsonValue<V> + ?Sized> ToJsonValue<V> for &T {
122    #[inline]
123    fn to_json_value(&self) -> V {
124        (*self).to_json_value()
125    }
126}
127
128impl<V: JsonValue, T: ToJsonValue<V>> ToJsonValue<V> for Vec<T> {
129    #[inline]
130    fn to_json_value(&self) -> V {
131        V::array(self.iter().map(ToJsonValue::to_json_value))
132    }
133}
134
135impl<V: JsonValue, T: ToJsonValue<V>> ToJsonValue<V> for [T] {
136    #[inline]
137    fn to_json_value(&self) -> V {
138        V::array(self.iter().map(ToJsonValue::to_json_value))
139    }
140}
141
142impl<V: JsonValue, T: ToJsonValue<V>> ToJsonValue<V> for Option<T> {
143    #[inline]
144    fn to_json_value(&self) -> V {
145        match self {
146            Some(t) => t.to_json_value(),
147            None => V::null(),
148        }
149    }
150}
151
152impl<V: JsonValue, K, T, S> ToJsonValue<V> for HashMap<K, T, S>
153where
154    K: AsRef<str>,
155    T: ToJsonValue<V>,
156{
157    #[inline]
158    fn to_json_value(&self) -> V {
159        V::object(self.iter().map(|(k, v)| (k.as_ref().to_string(), v.to_json_value())))
160    }
161}
162
163impl<V: JsonValue, K, T> ToJsonValue<V> for BTreeMap<K, T>
164where
165    K: AsRef<str>,
166    T: ToJsonValue<V>,
167{
168    #[inline]
169    fn to_json_value(&self) -> V {
170        V::object(self.iter().map(|(k, v)| (k.as_ref().to_string(), v.to_json_value())))
171    }
172}