Skip to main content

template_model/
json_value.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use std::ops::Deref;
3
4/// An arbitrary JSON value (null, boolean, number, string, array, or object).
5#[derive(Debug, Clone, PartialEq)]
6pub struct JsonValue(pub serde_json::Value);
7
8impl JsonValue {
9    pub fn into_inner(self) -> serde_json::Value {
10        self.0
11    }
12}
13
14impl Deref for JsonValue {
15    type Target = serde_json::Value;
16    fn deref(&self) -> &serde_json::Value {
17        &self.0
18    }
19}
20
21impl From<serde_json::Value> for JsonValue {
22    fn from(v: serde_json::Value) -> Self {
23        JsonValue(v)
24    }
25}
26
27impl From<JsonValue> for serde_json::Value {
28    fn from(v: JsonValue) -> Self {
29        v.0
30    }
31}
32
33impl Serialize for JsonValue {
34    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
35        self.0.serialize(serializer)
36    }
37}
38
39impl<'de> Deserialize<'de> for JsonValue {
40    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
41        serde_json::Value::deserialize(deserializer).map(JsonValue)
42    }
43}
44
45#[cfg(feature = "uniffi-bindings")]
46use std::collections::HashMap;
47
48#[cfg(feature = "uniffi-bindings")]
49#[derive(Debug, Clone, uniffi::Enum)]
50pub enum JsonValueEnum {
51    Null,
52    Bool { value: bool },
53    Int { value: i64 },
54    Float { value: f64 },
55    String { value: String },
56    Array { items: Vec<JsonValueEnum> },
57    Object { entries: HashMap<String, JsonValueEnum> },
58}
59
60#[cfg(feature = "uniffi-bindings")]
61impl From<&serde_json::Value> for JsonValueEnum {
62    fn from(v: &serde_json::Value) -> Self {
63        match v {
64            serde_json::Value::Null => JsonValueEnum::Null,
65            serde_json::Value::Bool(b) => JsonValueEnum::Bool { value: *b },
66            serde_json::Value::Number(n) => {
67                if let Some(i) = n.as_i64() {
68                    JsonValueEnum::Int { value: i }
69                } else {
70                    JsonValueEnum::Float { value: n.as_f64().unwrap_or(0.0) }
71                }
72            }
73            serde_json::Value::String(s) => JsonValueEnum::String { value: s.clone() },
74            serde_json::Value::Array(arr) => {
75                JsonValueEnum::Array { items: arr.iter().map(JsonValueEnum::from).collect() }
76            }
77            serde_json::Value::Object(obj) => JsonValueEnum::Object {
78                entries: obj.iter().map(|(k, v)| (k.clone(), JsonValueEnum::from(v))).collect(),
79            },
80        }
81    }
82}
83
84#[cfg(feature = "uniffi-bindings")]
85impl From<JsonValueEnum> for serde_json::Value {
86    fn from(v: JsonValueEnum) -> Self {
87        match v {
88            JsonValueEnum::Null => serde_json::Value::Null,
89            JsonValueEnum::Bool { value } => serde_json::Value::Bool(value),
90            JsonValueEnum::Int { value } => serde_json::json!(value),
91            JsonValueEnum::Float { value } => {
92                serde_json::Number::from_f64(value).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)
93            }
94            JsonValueEnum::String { value } => serde_json::Value::String(value),
95            JsonValueEnum::Array { items } => serde_json::Value::Array(items.into_iter().map(Into::into).collect()),
96            JsonValueEnum::Object { entries } => {
97                serde_json::Value::Object(entries.into_iter().map(|(k, v)| (k, v.into())).collect())
98            }
99        }
100    }
101}
102
103#[cfg(feature = "uniffi-bindings")]
104uniffi::custom_type!(JsonValue, JsonValueEnum, {
105    lower: |v| JsonValueEnum::from(&v.0),
106    try_lift: |e| Ok(JsonValue(serde_json::Value::from(e))),
107});
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112    use serde_json::json;
113
114    #[test]
115    fn serde_round_trips_nested_object() {
116        let original = JsonValue(json!({"key": [1, "two", true, null]}));
117        let serialized = serde_json::to_string(&original).unwrap();
118        let deserialized: JsonValue = serde_json::from_str(&serialized).unwrap();
119        assert_eq!(original, deserialized);
120    }
121
122    #[test]
123    fn serde_round_trips_null() {
124        let original = JsonValue(json!(null));
125        let serialized = serde_json::to_string(&original).unwrap();
126        assert_eq!(serialized, "null");
127        let deserialized: JsonValue = serde_json::from_str(&serialized).unwrap();
128        assert_eq!(original, deserialized);
129    }
130
131    #[test]
132    fn serde_round_trips_all_primitive_types() {
133        for value in [json!(42), json!(3.14), json!(true), json!("hello")] {
134            let jv = JsonValue(value.clone());
135            let json = serde_json::to_string(&jv).unwrap();
136            let back: JsonValue = serde_json::from_str(&json).unwrap();
137            assert_eq!(jv, back);
138        }
139    }
140
141    #[test]
142    fn deref_delegates_to_inner_value_methods() {
143        let jv = JsonValue(json!("hello"));
144        assert_eq!(jv.as_str(), Some("hello"));
145
146        let jv = JsonValue(json!(42));
147        assert_eq!(jv.as_i64(), Some(42));
148
149        let jv = JsonValue(json!(true));
150        assert_eq!(jv.as_bool(), Some(true));
151    }
152
153    #[test]
154    fn into_inner_unwraps_to_serde_value() {
155        let jv = JsonValue(json!({"a": 1}));
156        let inner: serde_json::Value = jv.into_inner();
157        assert_eq!(inner, json!({"a": 1}));
158    }
159
160    #[test]
161    fn from_conversions_round_trip_through_serde_value() {
162        let raw = json!({"nested": [1, 2]});
163        let jv: JsonValue = raw.clone().into();
164        let back: serde_json::Value = jv.into();
165        assert_eq!(raw, back);
166    }
167}