1use std::fmt;
5use std::rc::Rc;
6
7use indexmap::IndexMap;
8use serde::de::{self, Deserializer, MapAccess, SeqAccess, Visitor};
9use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
10
11#[derive(Clone, Debug)]
17pub enum JValue {
18 Null,
20 Bool(bool),
21 Number(f64),
22 String(Rc<str>),
23 Array(Rc<Vec<JValue>>),
24 Object(Rc<IndexMap<String, JValue>>),
25
26 Undefined,
28 Lambda {
29 lambda_id: Rc<str>,
30 params: Rc<Vec<String>>,
31 name: Option<Rc<str>>,
32 signature: Option<Rc<str>>,
33 },
34 Builtin {
35 name: Rc<str>,
36 },
37 Regex {
38 pattern: Rc<str>,
39 flags: Rc<str>,
40 },
41
42 #[cfg(feature = "python")]
44 LazyPyDict(Rc<crate::lazy::LazyPyDict>),
45}
46
47impl JValue {
50 #[inline]
51 pub fn is_null(&self) -> bool {
52 matches!(self, JValue::Null)
53 }
54
55 #[inline]
56 pub fn is_undefined(&self) -> bool {
57 matches!(self, JValue::Undefined)
58 }
59
60 #[inline]
61 pub fn is_bool(&self) -> bool {
62 matches!(self, JValue::Bool(_))
63 }
64
65 #[inline]
66 pub fn is_number(&self) -> bool {
67 matches!(self, JValue::Number(_))
68 }
69
70 #[inline]
71 pub fn is_string(&self) -> bool {
72 matches!(self, JValue::String(_))
73 }
74
75 #[inline]
76 pub fn is_array(&self) -> bool {
77 matches!(self, JValue::Array(_))
78 }
79
80 #[inline]
81 pub fn is_object(&self) -> bool {
82 match self {
83 JValue::Object(_) => true,
84 #[cfg(feature = "python")]
85 JValue::LazyPyDict(_) => true,
86 _ => false,
87 }
88 }
89
90 #[inline]
94 pub fn is_lazy(&self) -> bool {
95 #[cfg(feature = "python")]
96 {
97 matches!(self, JValue::LazyPyDict(_))
98 }
99 #[cfg(not(feature = "python"))]
100 {
101 false
102 }
103 }
104
105 #[inline]
106 pub fn is_lambda(&self) -> bool {
107 matches!(self, JValue::Lambda { .. })
108 }
109
110 #[inline]
111 pub fn is_builtin(&self) -> bool {
112 matches!(self, JValue::Builtin { .. })
113 }
114
115 #[inline]
116 pub fn is_function(&self) -> bool {
117 matches!(self, JValue::Lambda { .. } | JValue::Builtin { .. })
118 }
119
120 #[inline]
121 pub fn is_regex(&self) -> bool {
122 matches!(self, JValue::Regex { .. })
123 }
124}
125
126impl JValue {
129 #[inline]
130 pub fn as_f64(&self) -> Option<f64> {
131 match self {
132 JValue::Number(n) => Some(*n),
133 _ => None,
134 }
135 }
136
137 #[inline]
138 pub fn as_i64(&self) -> Option<i64> {
139 match self {
140 JValue::Number(n) => {
141 let f = *n;
142 if f.fract() == 0.0 && f >= i64::MIN as f64 && f <= i64::MAX as f64 {
143 Some(f as i64)
144 } else {
145 None
146 }
147 }
148 _ => None,
149 }
150 }
151
152 #[inline]
153 pub fn as_str(&self) -> Option<&str> {
154 match self {
155 JValue::String(s) => Some(s),
156 _ => None,
157 }
158 }
159
160 #[inline]
161 pub fn as_bool(&self) -> Option<bool> {
162 match self {
163 JValue::Bool(b) => Some(*b),
164 _ => None,
165 }
166 }
167
168 #[inline]
169 pub fn as_array(&self) -> Option<&Vec<JValue>> {
170 match self {
171 JValue::Array(arr) => Some(arr),
172 _ => None,
173 }
174 }
175
176 #[inline]
177 pub fn as_object(&self) -> Option<&IndexMap<String, JValue>> {
178 match self {
179 JValue::Object(map) => Some(map),
180 #[cfg(feature = "python")]
181 JValue::LazyPyDict(lazy) => lazy.to_object_ref(),
182 _ => None,
183 }
184 }
185
186 #[inline]
188 pub fn as_array_mut(&mut self) -> Option<&mut Vec<JValue>> {
189 match self {
190 JValue::Array(arr) => Some(Rc::make_mut(arr)),
191 _ => None,
192 }
193 }
194
195 #[inline]
197 pub fn as_object_mut(&mut self) -> Option<&mut IndexMap<String, JValue>> {
198 match self {
199 JValue::Object(map) => Some(Rc::make_mut(map)),
200 _ => None,
201 }
202 }
203
204 #[inline]
206 pub fn as_rc_str(&self) -> Option<&Rc<str>> {
207 match self {
208 JValue::String(s) => Some(s),
209 _ => None,
210 }
211 }
212
213 #[inline]
215 pub fn get(&self, key: &str) -> Option<&JValue> {
216 match self {
217 JValue::Object(map) => map.get(key),
218 _ => None,
219 }
220 }
221
222 #[inline]
224 pub fn get_index(&self, index: usize) -> Option<&JValue> {
225 match self {
226 JValue::Array(arr) => arr.get(index),
227 _ => None,
228 }
229 }
230}
231
232impl JValue {
235 #[inline]
236 pub fn from_i64(n: i64) -> Self {
237 JValue::Number(n as f64)
238 }
239
240 #[inline]
241 pub fn from_f64(n: f64) -> Self {
242 JValue::Number(n)
243 }
244
245 #[inline]
246 pub fn string(s: impl Into<Rc<str>>) -> Self {
247 JValue::String(s.into())
248 }
249
250 #[inline]
251 pub fn array(v: Vec<JValue>) -> Self {
252 JValue::Array(Rc::new(v))
253 }
254
255 #[inline]
256 pub fn object(m: IndexMap<String, JValue>) -> Self {
257 JValue::Object(Rc::new(m))
258 }
259
260 #[inline]
261 pub fn lambda(
262 lambda_id: impl Into<Rc<str>>,
263 params: Vec<String>,
264 name: Option<impl Into<Rc<str>>>,
265 signature: Option<impl Into<Rc<str>>>,
266 ) -> Self {
267 JValue::Lambda {
268 lambda_id: lambda_id.into(),
269 params: Rc::new(params),
270 name: name.map(|n| n.into()),
271 signature: signature.map(|s| s.into()),
272 }
273 }
274
275 #[inline]
276 pub fn builtin(name: impl Into<Rc<str>>) -> Self {
277 JValue::Builtin { name: name.into() }
278 }
279
280 #[inline]
281 pub fn regex(pattern: impl Into<Rc<str>>, flags: impl Into<Rc<str>>) -> Self {
282 JValue::Regex {
283 pattern: pattern.into(),
284 flags: flags.into(),
285 }
286 }
287}
288
289impl From<bool> for JValue {
292 #[inline]
293 fn from(b: bool) -> Self {
294 JValue::Bool(b)
295 }
296}
297
298impl From<i64> for JValue {
299 #[inline]
300 fn from(n: i64) -> Self {
301 JValue::Number(n as f64)
302 }
303}
304
305impl From<i32> for JValue {
306 #[inline]
307 fn from(n: i32) -> Self {
308 JValue::Number(n as f64)
309 }
310}
311
312impl From<u64> for JValue {
313 #[inline]
314 fn from(n: u64) -> Self {
315 JValue::Number(n as f64)
316 }
317}
318
319impl From<usize> for JValue {
320 #[inline]
321 fn from(n: usize) -> Self {
322 JValue::Number(n as f64)
323 }
324}
325
326impl From<f64> for JValue {
327 #[inline]
328 fn from(n: f64) -> Self {
329 JValue::Number(n)
330 }
331}
332
333impl From<&str> for JValue {
334 #[inline]
335 fn from(s: &str) -> Self {
336 JValue::String(s.into())
337 }
338}
339
340impl From<String> for JValue {
341 #[inline]
342 fn from(s: String) -> Self {
343 JValue::String(s.into())
344 }
345}
346
347impl From<Rc<str>> for JValue {
348 #[inline]
349 fn from(s: Rc<str>) -> Self {
350 JValue::String(s)
351 }
352}
353
354impl From<Vec<JValue>> for JValue {
355 #[inline]
356 fn from(v: Vec<JValue>) -> Self {
357 JValue::Array(Rc::new(v))
358 }
359}
360
361impl From<IndexMap<String, JValue>> for JValue {
362 #[inline]
363 fn from(m: IndexMap<String, JValue>) -> Self {
364 JValue::Object(Rc::new(m))
365 }
366}
367
368impl PartialEq for JValue {
371 fn eq(&self, other: &Self) -> bool {
372 match (self, other) {
373 (JValue::Null, JValue::Null) => true,
374 (JValue::Undefined, JValue::Undefined) => true,
375 (JValue::Bool(a), JValue::Bool(b)) => a == b,
376 (JValue::Number(a), JValue::Number(b)) => {
377 if a.is_nan() && b.is_nan() {
379 return false;
380 }
381 a == b
382 }
383 (JValue::String(a), JValue::String(b)) => a == b,
384 (JValue::Array(a), JValue::Array(b)) => a == b,
385 (JValue::Object(a), JValue::Object(b)) => a == b,
386 (JValue::Lambda { lambda_id: a, .. }, JValue::Lambda { lambda_id: b, .. }) => a == b,
387 (JValue::Builtin { name: a }, JValue::Builtin { name: b }) => a == b,
388 (
389 JValue::Regex {
390 pattern: ap,
391 flags: af,
392 },
393 JValue::Regex {
394 pattern: bp,
395 flags: bf,
396 },
397 ) => ap == bp && af == bf,
398 #[cfg(feature = "python")]
407 (JValue::LazyPyDict(a), JValue::LazyPyDict(b)) => {
408 Rc::ptr_eq(a, b)
409 || a.same_object(b)
410 || matches!((a.to_object_ref(), b.to_object_ref()), (Some(x), Some(y)) if x == y)
411 }
412 #[cfg(feature = "python")]
413 (JValue::LazyPyDict(a), JValue::Object(b)) => {
414 a.to_object_ref().is_some_and(|x| x == &**b)
415 }
416 #[cfg(feature = "python")]
417 (JValue::Object(a), JValue::LazyPyDict(b)) => {
418 b.to_object_ref().is_some_and(|x| &**a == x)
419 }
420 _ => false,
421 }
422 }
423}
424
425impl fmt::Display for JValue {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 match self {
430 JValue::Null => write!(f, "null"),
431 JValue::Undefined => write!(f, "undefined"),
432 JValue::Bool(b) => write!(f, "{}", b),
433 JValue::Number(n) => format_number(*n, f),
434 JValue::String(s) => write!(f, "\"{}\"", escape_json_string(s)),
435 JValue::Array(arr) => {
436 write!(f, "[")?;
437 for (i, v) in arr.iter().enumerate() {
438 if i > 0 {
439 write!(f, ",")?;
440 }
441 write!(f, "{}", v)?;
442 }
443 write!(f, "]")
444 }
445 JValue::Object(map) => {
446 write!(f, "{{")?;
447 for (i, (k, v)) in map.iter().enumerate() {
448 if i > 0 {
449 write!(f, ",")?;
450 }
451 write!(f, "\"{}\":{}", escape_json_string(k), v)?;
452 }
453 write!(f, "}}")
454 }
455 JValue::Lambda { lambda_id, .. } => write!(f, "\"<lambda:{}>\"", lambda_id),
456 JValue::Builtin { name } => write!(f, "\"<builtin:{}>\"", name),
457 JValue::Regex { pattern, flags } => write!(f, "\"<regex:/{}/{}>\"", pattern, flags),
458 #[cfg(feature = "python")]
459 JValue::LazyPyDict(lazy) => match lazy.to_object() {
460 Ok(map) => write!(f, "{}", JValue::Object(map)),
461 Err(_) => write!(f, "{{}}"),
462 },
463 }
464 }
465}
466
467fn escape_json_string(s: &str) -> String {
468 let mut result = String::with_capacity(s.len());
469 for c in s.chars() {
470 match c {
471 '"' => result.push_str("\\\""),
472 '\\' => result.push_str("\\\\"),
473 '\n' => result.push_str("\\n"),
474 '\r' => result.push_str("\\r"),
475 '\t' => result.push_str("\\t"),
476 c if c < '\x20' => {
477 result.push_str(&format!("\\u{:04x}", c as u32));
478 }
479 c => result.push(c),
480 }
481 }
482 result
483}
484
485fn format_number(n: f64, f: &mut fmt::Formatter<'_>) -> fmt::Result {
486 if !n.is_finite() {
487 write!(f, "null")
489 } else if n.fract() == 0.0 && n.abs() < 1e20 {
490 write!(f, "{}", n as i64)
491 } else {
492 write!(f, "{}", n)
494 }
495}
496
497impl Serialize for JValue {
500 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
501 where
502 S: Serializer,
503 {
504 match self {
505 JValue::Null => serializer.serialize_none(),
506 JValue::Undefined => serializer.serialize_none(),
507 JValue::Bool(b) => serializer.serialize_bool(*b),
508 JValue::Number(n) => {
509 if n.is_nan() || n.is_infinite() {
510 serializer.serialize_none()
511 } else if n.fract() == 0.0 && *n >= i64::MIN as f64 && *n <= i64::MAX as f64 {
512 serializer.serialize_i64(*n as i64)
513 } else {
514 serializer.serialize_f64(*n)
515 }
516 }
517 JValue::String(s) => serializer.serialize_str(s),
518 JValue::Array(arr) => {
519 let mut seq = serializer.serialize_seq(Some(arr.len()))?;
520 for v in arr.iter() {
521 seq.serialize_element(v)?;
522 }
523 seq.end()
524 }
525 JValue::Object(map) => {
526 let mut m = serializer.serialize_map(Some(map.len()))?;
527 for (k, v) in map.iter() {
528 m.serialize_entry(k, v)?;
529 }
530 m.end()
531 }
532 JValue::Lambda { .. } => serializer.serialize_str(""),
533 JValue::Builtin { .. } => serializer.serialize_str(""),
534 JValue::Regex { pattern, flags } => {
535 let mut m = serializer.serialize_map(Some(2))?;
536 m.serialize_entry("pattern", &**pattern)?;
537 m.serialize_entry("flags", &**flags)?;
538 m.end()
539 }
540 #[cfg(feature = "python")]
541 JValue::LazyPyDict(lazy) => match lazy.to_object() {
542 Ok(map) => {
543 let mut m = serializer.serialize_map(Some(map.len()))?;
544 for (k, v) in map.iter() {
545 m.serialize_entry(k, v)?;
546 }
547 m.end()
548 }
549 Err(e) => Err(serde::ser::Error::custom(e.0)),
550 },
551 }
552 }
553}
554
555impl<'de> serde::Deserialize<'de> for JValue {
558 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
559 where
560 D: Deserializer<'de>,
561 {
562 deserializer.deserialize_any(JValueVisitor)
563 }
564}
565
566struct JValueVisitor;
567
568impl<'de> Visitor<'de> for JValueVisitor {
569 type Value = JValue;
570
571 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
572 write!(f, "any valid JSON value")
573 }
574
575 fn visit_bool<E: de::Error>(self, v: bool) -> Result<JValue, E> {
576 Ok(JValue::Bool(v))
577 }
578
579 fn visit_i64<E: de::Error>(self, v: i64) -> Result<JValue, E> {
580 Ok(JValue::Number(v as f64))
581 }
582
583 fn visit_u64<E: de::Error>(self, v: u64) -> Result<JValue, E> {
584 Ok(JValue::Number(v as f64))
585 }
586
587 fn visit_f64<E: de::Error>(self, v: f64) -> Result<JValue, E> {
588 Ok(JValue::Number(v))
589 }
590
591 fn visit_str<E: de::Error>(self, v: &str) -> Result<JValue, E> {
592 Ok(JValue::string(v))
593 }
594
595 fn visit_string<E: de::Error>(self, v: String) -> Result<JValue, E> {
596 Ok(JValue::String(v.into()))
597 }
598
599 fn visit_none<E: de::Error>(self) -> Result<JValue, E> {
600 Ok(JValue::Null)
601 }
602
603 fn visit_unit<E: de::Error>(self) -> Result<JValue, E> {
604 Ok(JValue::Null)
605 }
606
607 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<JValue, A::Error> {
608 let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or(0));
609 while let Some(elem) = seq.next_element()? {
610 vec.push(elem);
611 }
612 Ok(JValue::array(vec))
613 }
614
615 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<JValue, A::Error> {
616 let mut m = IndexMap::with_capacity(map.size_hint().unwrap_or(0));
617 while let Some((k, v)) = map.next_entry()? {
618 m.insert(k, v);
619 }
620 Ok(JValue::object(m))
621 }
622}
623
624impl JValue {
627 pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
629 serde_json::to_string(self)
630 }
631
632 pub fn to_json_string_pretty(&self) -> Result<String, serde_json::Error> {
634 serde_json::to_string_pretty(self)
635 }
636
637 pub fn from_json_str(s: &str) -> Result<JValue, serde_json::Error> {
652 #[cfg(feature = "simd")]
653 {
654 thread_local! {
655 static SCRATCH: std::cell::RefCell<(Vec<u8>, simd_json::Buffers)> =
656 std::cell::RefCell::new((Vec::new(), simd_json::Buffers::new(0)));
657 }
658
659 let result = SCRATCH.with(|scratch| {
660 let (bytes, buffers) = &mut *scratch.borrow_mut();
661 bytes.clear();
662 bytes.extend_from_slice(s.as_bytes());
663 simd_json::serde::from_slice_with_buffers::<JValue>(bytes, buffers)
664 });
665 if let Ok(value) = result {
666 return Ok(value);
667 }
668 }
670 serde_json::from_str(s)
671 }
672}
673
674impl From<serde_json::Value> for JValue {
677 fn from(v: serde_json::Value) -> Self {
678 match v {
679 serde_json::Value::Null => JValue::Null,
680 serde_json::Value::Bool(b) => JValue::Bool(b),
681 serde_json::Value::Number(n) => JValue::Number(n.as_f64().unwrap_or(0.0)),
682 serde_json::Value::String(s) => JValue::String(s.into()),
683 serde_json::Value::Array(arr) => {
684 JValue::Array(Rc::new(arr.into_iter().map(JValue::from).collect()))
685 }
686 serde_json::Value::Object(map) => {
687 let m: IndexMap<String, JValue> =
688 map.into_iter().map(|(k, v)| (k, JValue::from(v))).collect();
689 JValue::Object(Rc::new(m))
690 }
691 }
692 }
693}
694
695impl From<&JValue> for serde_json::Value {
698 fn from(v: &JValue) -> Self {
699 match v {
700 JValue::Null | JValue::Undefined => serde_json::Value::Null,
701 JValue::Bool(b) => serde_json::Value::Bool(*b),
702 JValue::Number(n) => {
703 if n.is_nan() || n.is_infinite() {
704 serde_json::Value::Null
705 } else {
706 serde_json::json!(*n)
707 }
708 }
709 JValue::String(s) => serde_json::Value::String(s.to_string()),
710 JValue::Array(arr) => {
711 serde_json::Value::Array(arr.iter().map(serde_json::Value::from).collect())
712 }
713 JValue::Object(map) => {
714 let m: serde_json::Map<String, serde_json::Value> = map
715 .iter()
716 .map(|(k, v)| (k.clone(), serde_json::Value::from(v)))
717 .collect();
718 serde_json::Value::Object(m)
719 }
720 JValue::Lambda { .. } | JValue::Builtin { .. } => serde_json::Value::Null,
721 JValue::Regex { pattern, flags } => {
722 let mut m = serde_json::Map::new();
723 m.insert(
724 "pattern".to_string(),
725 serde_json::Value::String(pattern.to_string()),
726 );
727 m.insert(
728 "flags".to_string(),
729 serde_json::Value::String(flags.to_string()),
730 );
731 serde_json::Value::Object(m)
732 }
733 #[cfg(feature = "python")]
734 JValue::LazyPyDict(lazy) => match lazy.to_object() {
735 Ok(map) => {
736 let m: serde_json::Map<String, serde_json::Value> = map
737 .iter()
738 .map(|(k, v)| (k.clone(), serde_json::Value::from(v)))
739 .collect();
740 serde_json::Value::Object(m)
741 }
742 Err(_) => serde_json::Value::Object(serde_json::Map::new()),
743 },
744 }
745 }
746}
747
748#[macro_export]
763macro_rules! jvalue {
764 (null) => {
766 $crate::value::JValue::Null
767 };
768
769 (true) => {
771 $crate::value::JValue::Bool(true)
772 };
773
774 (false) => {
776 $crate::value::JValue::Bool(false)
777 };
778
779 ([ $($elem:tt),* $(,)? ]) => {
781 $crate::value::JValue::Array(std::rc::Rc::new(vec![ $( jvalue!($elem) ),* ]))
782 };
783
784 ({ $($key:tt : $val:tt),* $(,)? }) => {
786 {
787 let mut map = indexmap::IndexMap::new();
788 $(
789 map.insert(($key).to_string(), jvalue!($val));
790 )*
791 $crate::value::JValue::Object(std::rc::Rc::new(map))
792 }
793 };
794
795 ($other:expr) => {
797 $crate::value::JValue::from($other)
798 };
799}
800
801#[cfg(test)]
804mod tests {
805 use super::*;
806
807 #[test]
808 fn test_clone_is_cheap() {
809 let arr = JValue::array(vec![
811 JValue::from(1i64),
812 JValue::from(2i64),
813 JValue::from(3i64),
814 ]);
815 let arr2 = arr.clone();
816 if let (JValue::Array(a), JValue::Array(b)) = (&arr, &arr2) {
817 assert!(Rc::ptr_eq(a, b));
818 } else {
819 panic!("expected arrays");
820 }
821
822 let mut map = IndexMap::new();
824 map.insert("x".to_string(), JValue::from(1i64));
825 let obj = JValue::object(map);
826 let obj2 = obj.clone();
827 if let (JValue::Object(a), JValue::Object(b)) = (&obj, &obj2) {
828 assert!(Rc::ptr_eq(a, b));
829 } else {
830 panic!("expected objects");
831 }
832
833 let s = JValue::string("hello");
835 let s2 = s.clone();
836 if let (JValue::String(a), JValue::String(b)) = (&s, &s2) {
837 assert!(Rc::ptr_eq(a, b));
838 } else {
839 panic!("expected strings");
840 }
841 }
842
843 #[test]
844 fn test_type_checks() {
845 assert!(JValue::Null.is_null());
846 assert!(JValue::Undefined.is_undefined());
847 assert!(JValue::Bool(true).is_bool());
848 assert!(JValue::Number(42.0).is_number());
849 assert!(JValue::string("hello").is_string());
850 assert!(JValue::array(vec![]).is_array());
851 assert!(JValue::object(IndexMap::new()).is_object());
852 assert!(JValue::lambda("id", vec![], None::<&str>, None::<&str>).is_lambda());
853 assert!(JValue::lambda("id", vec![], None::<&str>, None::<&str>).is_function());
854 assert!(JValue::builtin("sum").is_builtin());
855 assert!(JValue::builtin("sum").is_function());
856 assert!(JValue::regex(".*", "i").is_regex());
857 }
858
859 #[test]
860 fn test_extraction() {
861 assert_eq!(JValue::Number(42.0).as_f64(), Some(42.0));
862 assert_eq!(JValue::Number(42.0).as_i64(), Some(42));
863 assert_eq!(JValue::Number(42.5).as_i64(), None);
864 assert_eq!(JValue::string("hello").as_str(), Some("hello"));
865 assert_eq!(JValue::Bool(true).as_bool(), Some(true));
866 assert_eq!(
867 JValue::array(vec![JValue::from(1i64)])
868 .as_array()
869 .map(|a| a.len()),
870 Some(1)
871 );
872 }
873
874 #[test]
875 fn test_jvalue_macro() {
876 let n = jvalue!(null);
877 assert!(n.is_null());
878
879 let b = jvalue!(true);
880 assert_eq!(b.as_bool(), Some(true));
881
882 let arr = jvalue!([1i64, 2i64, 3i64]);
883 assert_eq!(arr.as_array().map(|a| a.len()), Some(3));
884
885 let obj = jvalue!({"name": "Alice", "age": 30i64});
886 assert_eq!(obj.get("name").and_then(|v| v.as_str()), Some("Alice"));
887 }
888
889 #[test]
890 fn test_equality() {
891 assert_eq!(JValue::Null, JValue::Null);
892 assert_eq!(JValue::Bool(true), JValue::Bool(true));
893 assert_ne!(JValue::Bool(true), JValue::Bool(false));
894 assert_eq!(JValue::Number(42.0), JValue::Number(42.0));
895 assert_ne!(JValue::Number(f64::NAN), JValue::Number(f64::NAN));
896 assert_eq!(JValue::string("hello"), JValue::string("hello"));
897 assert_ne!(JValue::Null, JValue::Undefined);
898 }
899
900 #[test]
901 fn test_serde_roundtrip() {
902 let v = jvalue!({"name": "Alice", "scores": [1i64, 2i64, 3i64], "active": true});
903 let json_str = v.to_json_string().unwrap();
904 let parsed = JValue::from_json_str(&json_str).unwrap();
905 assert_eq!(v, parsed);
906 }
907
908 #[test]
909 fn test_from_serde_json() {
910 let sv = serde_json::json!({"name": "Alice", "age": 30, "scores": [1, 2, 3]});
911 let jv = JValue::from(sv);
912 assert_eq!(jv.get("name").and_then(|v| v.as_str()), Some("Alice"));
913 assert_eq!(jv.get("age").and_then(|v| v.as_f64()), Some(30.0));
914 }
915
916 #[test]
917 fn test_make_mut() {
918 let mut arr = JValue::array(vec![JValue::from(1i64), JValue::from(2i64)]);
919 let arr2 = arr.clone();
920
921 arr.as_array_mut().unwrap().push(JValue::from(3i64));
923
924 assert_eq!(arr.as_array().unwrap().len(), 3);
926 assert_eq!(arr2.as_array().unwrap().len(), 2);
927 }
928}