1use std::fmt;
8
9#[derive(Debug, Clone, PartialEq)]
13pub enum Value {
14 Null,
16 Bool(bool),
18 UInt(u64),
20 Int(i64),
22 Float(f64),
24 Str(String),
26 Bytes(Vec<u8>),
28 Array(Vec<Value>),
30 Object(Vec<(String, Value)>),
33}
34
35impl Value {
36 pub fn type_name(&self) -> &'static str {
38 match self {
39 Value::Null => "null",
40 Value::Bool(_) => "bool",
41 Value::UInt(_) => "uint",
42 Value::Int(_) => "int",
43 Value::Float(_) => "float",
44 Value::Str(_) => "str",
45 Value::Bytes(_) => "bytes",
46 Value::Array(_) => "array",
47 Value::Object(_) => "object",
48 }
49 }
50
51 pub fn is_null(&self) -> bool {
53 matches!(self, Value::Null)
54 }
55
56 pub fn as_str(&self) -> Option<&str> {
58 match self {
59 Value::Str(s) => Some(s),
60 _ => None,
61 }
62 }
63
64 pub fn as_uint(&self) -> Option<u64> {
66 match self {
67 Value::UInt(n) => Some(*n),
68 _ => None,
69 }
70 }
71
72 pub fn as_int(&self) -> Option<i64> {
74 match self {
75 Value::Int(n) => Some(*n),
76 _ => None,
77 }
78 }
79
80 pub fn as_float(&self) -> Option<f64> {
82 match self {
83 Value::Float(n) => Some(*n),
84 _ => None,
85 }
86 }
87
88 pub fn as_bool(&self) -> Option<bool> {
90 match self {
91 Value::Bool(b) => Some(*b),
92 _ => None,
93 }
94 }
95
96 pub fn as_array(&self) -> Option<&[Value]> {
98 match self {
99 Value::Array(a) => Some(a),
100 _ => None,
101 }
102 }
103
104 pub fn as_object(&self) -> Option<&[(String, Value)]> {
106 match self {
107 Value::Object(o) => Some(o),
108 _ => None,
109 }
110 }
111}
112
113impl fmt::Display for Value {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 match self {
116 Value::Null => write!(f, "null"),
117 Value::Bool(b) => write!(f, "{b}"),
118 Value::UInt(n) => write!(f, "{n}"),
119 Value::Int(n) => write!(f, "{n}"),
120 Value::Float(n) => write!(f, "{n}"),
121 Value::Str(s) => write!(f, "\"{s}\""),
122 Value::Bytes(b) => write!(
123 f,
124 "b64#{}",
125 base64::engine::general_purpose::STANDARD.encode(b)
126 ),
127 Value::Array(items) => {
128 write!(f, "[")?;
129 for (i, item) in items.iter().enumerate() {
130 if i > 0 {
131 write!(f, ", ")?;
132 }
133 write!(f, "{item}")?;
134 }
135 write!(f, "]")
136 }
137 Value::Object(entries) => {
138 write!(f, "{{ ")?;
139 for (i, (k, v)) in entries.iter().enumerate() {
140 if i > 0 {
141 write!(f, " ")?;
142 }
143 write!(f, "{k}: {v};")?;
144 }
145 write!(f, " }}")
146 }
147 }
148 }
149}
150
151use base64::Engine;
152
153#[derive(Debug, Clone, PartialEq)]
158pub enum CrousValue<'a> {
159 Null,
160 Bool(bool),
161 UInt(u64),
162 Int(i64),
163 Float(f64),
164 Str(&'a str),
166 Bytes(&'a [u8]),
168 Array(Vec<CrousValue<'a>>),
170 Object(Vec<(&'a str, CrousValue<'a>)>),
172}
173
174impl<'a> CrousValue<'a> {
175 pub fn to_owned_value(&self) -> Value {
177 match self {
178 CrousValue::Null => Value::Null,
179 CrousValue::Bool(b) => Value::Bool(*b),
180 CrousValue::UInt(n) => Value::UInt(*n),
181 CrousValue::Int(n) => Value::Int(*n),
182 CrousValue::Float(n) => Value::Float(*n),
183 CrousValue::Str(s) => Value::Str((*s).to_string()),
184 CrousValue::Bytes(b) => Value::Bytes(b.to_vec()),
185 CrousValue::Array(items) => {
186 Value::Array(items.iter().map(|v| v.to_owned_value()).collect())
187 }
188 CrousValue::Object(entries) => Value::Object(
189 entries
190 .iter()
191 .map(|(k, v)| ((*k).to_string(), v.to_owned_value()))
192 .collect(),
193 ),
194 }
195 }
196}
197
198impl From<&serde_json::Value> for Value {
200 fn from(jv: &serde_json::Value) -> Self {
201 match jv {
202 serde_json::Value::Null => Value::Null,
203 serde_json::Value::Bool(b) => Value::Bool(*b),
204 serde_json::Value::Number(n) => {
205 if let Some(u) = n.as_u64() {
206 Value::UInt(u)
207 } else if let Some(i) = n.as_i64() {
208 Value::Int(i)
209 } else if let Some(f) = n.as_f64() {
210 Value::Float(f)
211 } else {
212 Value::Null
213 }
214 }
215 serde_json::Value::String(s) => Value::Str(s.clone()),
216 serde_json::Value::Array(arr) => Value::Array(arr.iter().map(Value::from).collect()),
217 serde_json::Value::Object(map) => Value::Object(
218 map.iter()
219 .map(|(k, v)| (k.clone(), Value::from(v)))
220 .collect(),
221 ),
222 }
223 }
224}
225
226impl From<&Value> for serde_json::Value {
228 fn from(cv: &Value) -> Self {
229 match cv {
230 Value::Null => serde_json::Value::Null,
231 Value::Bool(b) => serde_json::Value::Bool(*b),
232 Value::UInt(n) => serde_json::json!(*n),
233 Value::Int(n) => serde_json::json!(*n),
234 Value::Float(n) => serde_json::json!(*n),
235 Value::Str(s) => serde_json::Value::String(s.clone()),
236 Value::Bytes(b) => {
237 serde_json::Value::String(base64::engine::general_purpose::STANDARD.encode(b))
238 }
239 Value::Array(items) => {
240 serde_json::Value::Array(items.iter().map(serde_json::Value::from).collect())
241 }
242 Value::Object(entries) => {
243 let map: serde_json::Map<String, serde_json::Value> = entries
244 .iter()
245 .map(|(k, v)| (k.clone(), serde_json::Value::from(v)))
246 .collect();
247 serde_json::Value::Object(map)
248 }
249 }
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[test]
258 fn value_type_names() {
259 assert_eq!(Value::Null.type_name(), "null");
260 assert_eq!(Value::Bool(true).type_name(), "bool");
261 assert_eq!(Value::UInt(42).type_name(), "uint");
262 assert_eq!(Value::Str("hi".into()).type_name(), "str");
263 }
264
265 #[test]
266 fn crous_value_to_owned() {
267 let cv = CrousValue::Object(vec![
268 ("name", CrousValue::Str("Alice")),
269 ("age", CrousValue::UInt(30)),
270 ]);
271 let owned = cv.to_owned_value();
272 assert_eq!(
273 owned,
274 Value::Object(vec![
275 ("name".into(), Value::Str("Alice".into())),
276 ("age".into(), Value::UInt(30)),
277 ])
278 );
279 }
280
281 #[test]
282 fn json_roundtrip() {
283 let cv = Value::Object(vec![
284 ("name".into(), Value::Str("Bob".into())),
285 ("score".into(), Value::Float(99.5)),
286 ]);
287 let jv = serde_json::Value::from(&cv);
288 let back = Value::from(&jv);
289 match &back {
291 Value::Object(entries) => {
292 assert_eq!(entries[0].0, "name");
293 assert_eq!(entries[1].0, "score");
294 }
295 _ => panic!("expected object"),
296 }
297 }
298}