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