pjson_rs_domain/value_objects/
json_data.rs1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::fmt;
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
13pub enum JsonData {
14 #[default]
15 Null,
17 Bool(bool),
19 Integer(i64),
21 Float(f64),
23 String(String),
25 Array(Vec<JsonData>),
27 Object(HashMap<String, JsonData>),
29}
30
31impl JsonData {
32 pub fn null() -> Self {
34 Self::Null
35 }
36
37 pub fn bool(value: bool) -> Self {
39 Self::Bool(value)
40 }
41
42 pub fn integer(value: i64) -> Self {
44 Self::Integer(value)
45 }
46
47 pub fn float(value: f64) -> Self {
49 Self::Float(value)
50 }
51
52 pub fn string<S: Into<String>>(value: S) -> Self {
54 Self::String(value.into())
55 }
56
57 pub fn array(values: Vec<JsonData>) -> Self {
59 Self::Array(values)
60 }
61
62 pub fn object(values: HashMap<String, JsonData>) -> Self {
64 Self::Object(values)
65 }
66
67 pub fn is_null(&self) -> bool {
69 matches!(self, Self::Null)
70 }
71
72 pub fn is_bool(&self) -> bool {
74 matches!(self, Self::Bool(_))
75 }
76
77 pub fn is_integer(&self) -> bool {
79 matches!(self, Self::Integer(_))
80 }
81
82 pub fn is_float(&self) -> bool {
84 matches!(self, Self::Float(_))
85 }
86
87 pub fn is_number(&self) -> bool {
89 matches!(self, Self::Integer(_) | Self::Float(_))
90 }
91
92 pub fn is_string(&self) -> bool {
94 matches!(self, Self::String(_))
95 }
96
97 pub fn is_array(&self) -> bool {
99 matches!(self, Self::Array(_))
100 }
101
102 pub fn is_object(&self) -> bool {
104 matches!(self, Self::Object(_))
105 }
106
107 pub fn as_bool(&self) -> Option<bool> {
109 match self {
110 Self::Bool(b) => Some(*b),
111 _ => None,
112 }
113 }
114
115 pub fn as_i64(&self) -> Option<i64> {
117 match self {
118 Self::Integer(i) => Some(*i),
119 _ => None,
120 }
121 }
122
123 pub fn as_f64(&self) -> Option<f64> {
125 match self {
126 Self::Float(f) => Some(*f),
127 Self::Integer(i) => Some(*i as f64),
128 _ => None,
129 }
130 }
131
132 pub fn as_str(&self) -> Option<&str> {
134 match self {
135 Self::String(s) => Some(s),
136 _ => None,
137 }
138 }
139
140 pub fn as_array(&self) -> Option<&Vec<JsonData>> {
142 match self {
143 Self::Array(arr) => Some(arr),
144 _ => None,
145 }
146 }
147
148 pub fn as_array_mut(&mut self) -> Option<&mut Vec<JsonData>> {
150 match self {
151 Self::Array(arr) => Some(arr),
152 _ => None,
153 }
154 }
155
156 pub fn as_object(&self) -> Option<&HashMap<String, JsonData>> {
158 match self {
159 Self::Object(obj) => Some(obj),
160 _ => None,
161 }
162 }
163
164 pub fn as_object_mut(&mut self) -> Option<&mut HashMap<String, JsonData>> {
166 match self {
167 Self::Object(obj) => Some(obj),
168 _ => None,
169 }
170 }
171
172 pub fn get(&self, key: &str) -> Option<&JsonData> {
174 match self {
175 Self::Object(obj) => obj.get(key),
176 _ => None,
177 }
178 }
179
180 pub fn get_path(&self, path: &str) -> Option<&JsonData> {
182 let parts: Vec<&str> = path.split('.').collect();
183 let mut current = self;
184
185 for part in parts {
186 match current {
187 Self::Object(obj) => {
188 current = obj.get(part)?;
189 }
190 _ => return None,
191 }
192 }
193
194 Some(current)
195 }
196
197 pub fn set_path(&mut self, path: &str, value: JsonData) -> bool {
199 let parts: Vec<&str> = path.split('.').collect();
200 if parts.is_empty() {
201 return false;
202 }
203
204 if parts.len() == 1 {
205 if let Self::Object(obj) = self {
206 obj.insert(parts[0].to_string(), value);
207 return true;
208 }
209 return false;
210 }
211
212 let mut current = self;
214 for part in &parts[..parts.len() - 1] {
215 match current {
216 Self::Object(obj) => {
217 if !obj.contains_key(*part) {
218 obj.insert(part.to_string(), Self::object(HashMap::new()));
219 }
220 current = obj
221 .get_mut(*part)
222 .expect("Key must exist as we just inserted it above");
223 }
224 _ => return false,
225 }
226 }
227
228 if let Self::Object(obj) = current {
230 obj.insert(parts[parts.len() - 1].to_string(), value);
231 true
232 } else {
233 false
234 }
235 }
236
237 pub fn memory_size(&self) -> usize {
239 match self {
240 Self::Null => 1,
241 Self::Bool(_) => 1,
242 Self::Integer(_) => 8,
243 Self::Float(_) => 8,
244 Self::String(s) => s.len() * 2, Self::Array(arr) => 8 + arr.iter().map(|v| v.memory_size()).sum::<usize>(),
246 Self::Object(obj) => {
247 16 + obj
248 .iter()
249 .map(|(k, v)| k.len() * 2 + v.memory_size())
250 .sum::<usize>()
251 }
252 }
253 }
254}
255
256impl fmt::Display for JsonData {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 match self {
259 Self::Null => write!(f, "null"),
260 Self::Bool(b) => write!(f, "{b}"),
261 Self::Integer(i) => write!(f, "{i}"),
262 Self::Float(float_val) => write!(f, "{float_val}"),
263 Self::String(s) => write!(f, "\"{s}\""),
264 Self::Array(arr) => {
265 write!(f, "[")?;
266 for (i, item) in arr.iter().enumerate() {
267 if i > 0 {
268 write!(f, ",")?;
269 }
270 write!(f, "{item}")?;
271 }
272 write!(f, "]")
273 }
274 Self::Object(obj) => {
275 write!(f, "{{")?;
276 for (i, (key, value)) in obj.iter().enumerate() {
277 if i > 0 {
278 write!(f, ",")?;
279 }
280 write!(f, "\"{key}\":{value}")?;
281 }
282 write!(f, "}}")
283 }
284 }
285 }
286}
287
288impl Eq for JsonData {}
289
290impl std::hash::Hash for JsonData {
291 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
292 match self {
293 Self::Null => 0u8.hash(state),
294 Self::Bool(b) => {
295 1u8.hash(state);
296 b.hash(state);
297 }
298 Self::Integer(i) => {
299 2u8.hash(state);
300 i.hash(state);
301 }
302 Self::Float(f) => {
303 3u8.hash(state);
304 f.to_bits().hash(state);
306 }
307 Self::String(s) => {
308 4u8.hash(state);
309 s.hash(state);
310 }
311 Self::Array(arr) => {
312 5u8.hash(state);
313 arr.hash(state);
314 }
315 Self::Object(obj) => {
316 6u8.hash(state);
317 let mut pairs: Vec<_> = obj.iter().collect();
320 pairs.sort_by_key(|(k, _)| *k);
321 pairs.hash(state);
322 }
323 }
324 }
325}
326
327impl From<bool> for JsonData {
328 fn from(value: bool) -> Self {
329 Self::Bool(value)
330 }
331}
332
333impl From<f64> for JsonData {
334 fn from(value: f64) -> Self {
335 Self::Float(value)
336 }
337}
338
339impl From<i64> for JsonData {
340 fn from(value: i64) -> Self {
341 Self::Integer(value)
342 }
343}
344
345impl From<String> for JsonData {
346 fn from(value: String) -> Self {
347 Self::String(value)
348 }
349}
350
351impl From<&str> for JsonData {
352 fn from(value: &str) -> Self {
353 Self::String(value.to_string())
354 }
355}
356
357impl From<Vec<JsonData>> for JsonData {
358 fn from(value: Vec<JsonData>) -> Self {
359 Self::Array(value)
360 }
361}
362
363impl From<HashMap<String, JsonData>> for JsonData {
364 fn from(value: HashMap<String, JsonData>) -> Self {
365 Self::Object(value)
366 }
367}
368
369impl From<serde_json::Value> for JsonData {
370 fn from(value: serde_json::Value) -> Self {
371 match value {
372 serde_json::Value::Null => Self::Null,
373 serde_json::Value::Bool(b) => Self::Bool(b),
374 serde_json::Value::Number(n) => {
375 if let Some(i) = n.as_i64() {
376 Self::Integer(i)
377 } else if let Some(f) = n.as_f64() {
378 Self::Float(f)
379 } else {
380 Self::Float(0.0) }
382 }
383 serde_json::Value::String(s) => Self::String(s),
384 serde_json::Value::Array(arr) => {
385 let converted: Vec<JsonData> = arr.into_iter().map(JsonData::from).collect();
386 Self::Array(converted)
387 }
388 serde_json::Value::Object(obj) => {
389 let converted: HashMap<String, JsonData> = obj
390 .into_iter()
391 .map(|(k, v)| (k, JsonData::from(v)))
392 .collect();
393 Self::Object(converted)
394 }
395 }
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use super::*;
402
403 #[test]
404 fn test_json_data_creation() {
405 assert_eq!(JsonData::null(), JsonData::Null);
406 assert_eq!(JsonData::bool(true), JsonData::Bool(true));
407 assert_eq!(JsonData::float(42.0), JsonData::Float(42.0));
408 assert_eq!(
409 JsonData::string("hello"),
410 JsonData::String("hello".to_string())
411 );
412 }
413
414 #[test]
415 fn test_json_data_type_checks() {
416 assert!(JsonData::null().is_null());
417 assert!(JsonData::bool(true).is_bool());
418 assert!(JsonData::float(42.0).is_number());
419 assert!(JsonData::string("hello").is_string());
420 assert!(JsonData::array(vec![]).is_array());
421 assert!(JsonData::object(HashMap::new()).is_object());
422 }
423
424 #[test]
425 fn test_json_data_conversions() {
426 assert_eq!(JsonData::bool(true).as_bool(), Some(true));
427 assert_eq!(JsonData::float(42.0).as_f64(), Some(42.0));
428 assert_eq!(JsonData::integer(42).as_i64(), Some(42));
429 assert_eq!(JsonData::string("hello").as_str(), Some("hello"));
430 }
431
432 #[test]
433 fn test_path_operations() {
434 let mut data = JsonData::object(HashMap::new());
435
436 assert!(data.set_path("user.name", JsonData::string("John")));
438 assert!(data.set_path("user.age", JsonData::integer(30)));
439
440 assert_eq!(data.get_path("user.name").unwrap().as_str(), Some("John"));
442 assert_eq!(data.get_path("user.age").unwrap().as_i64(), Some(30));
443
444 assert!(data.get_path("user.email").is_none());
446 }
447
448 #[test]
449 fn test_memory_size() {
450 let data = JsonData::object(
451 [
452 ("name".to_string(), JsonData::string("John")),
453 ("age".to_string(), JsonData::integer(30)),
454 ]
455 .into_iter()
456 .collect(),
457 );
458
459 assert!(data.memory_size() > 0);
460 }
461
462 #[test]
463 fn test_display() {
464 let data = JsonData::object(
465 [
466 ("name".to_string(), JsonData::string("John")),
467 ("active".to_string(), JsonData::bool(true)),
468 ]
469 .into_iter()
470 .collect(),
471 );
472
473 let display = format!("{data}");
474 assert!(display.contains("name"));
475 assert!(display.contains("John"));
476 }
477}