template_model/
json_value.rs1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use std::ops::Deref;
3
4#[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}