#[macro_export(local_inner_macros)]
macro_rules! json {
(true) => {
$crate::Value::new_bool(true, std::ptr::null())
};
(false) => {
$crate::Value::new_bool(false, std::ptr::null())
};
(null) => {
$crate::Value::new_null(std::ptr::null())
};
([]) => {
$crate::Array::new().into_value()
};
({}) => {
$crate::Object::new().into_value()
};
($($json:tt)+) => {
{
use $crate::JsonValueTrait;
let shared = unsafe { &*$crate::value::shared::Shared::new_ptr() };
let mut value = json_internal!(shared, $($json)+);
if value.is_number() {
unsafe {
drop(Box::from_raw(shared as *const _ as *mut $crate::value::shared::Shared));
}
value.mark_shared(std::ptr::null());
} else {
value.mark_root();
}
value
}
};
}
#[macro_export(local_inner_macros)]
macro_rules! array {
() => {
$crate::value::Array::new()
};
($($tt:tt)+) => {
{
let shared = unsafe { &*$crate::value::shared::Shared::new_ptr() };
let mut value = json_internal!(shared, [$($tt)+]);
value.mark_root();
value.into_array().expect("the literal is not a json array")
}
};
}
#[macro_export(local_inner_macros)]
macro_rules! object {
() => {
$crate::value::Object::new()
};
($($tt:tt)+) => {
{
let shared = unsafe { &*$crate::value::shared::Shared::new_ptr() };
let mut value = json_internal!(shared, {$($tt)+});
value.mark_root();
value.into_object().expect("the literal is not a json object")
}
};
}
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! json_internal {
(@array $shared:expr, [$($elems:expr,)*]) => {
json_internal_array![$shared, $($elems)*]
};
(@array $shared:expr, [$($elems:expr),*]) => {
json_internal_array![$shared, $($elems)*]
};
(@array $shared:expr, [$($elems:expr,)*] null $($rest:tt)*) => {
json_internal!(@array $shared, [$($elems,)* json_internal!($shared, null)] $($rest)*)
};
(@array $shared:expr, [$($elems:expr,)*] true $($rest:tt)*) => {
json_internal!(@array $shared, [$($elems,)* json_internal!($shared, true)] $($rest)*)
};
(@array $shared:expr, [$($elems:expr,)*] false $($rest:tt)*) => {
json_internal!(@array $shared, [$($elems,)* json_internal!($shared, false)] $($rest)*)
};
(@array $shared:expr, [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
json_internal!(@array $shared, [$($elems,)* json_internal!($shared, [$($array)*])] $($rest)*)
};
(@array $shared:expr, [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
json_internal!(@array $shared, [$($elems,)* json_internal!($shared, {$($map)*})] $($rest)*)
};
(@array $shared:expr, [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
json_internal!(@array $shared, [$($elems,)* json_internal!($shared, $next),] $($rest)*)
};
(@array $shared:expr, [$($elems:expr,)*] $last:expr) => {
json_internal!(@array $shared, [$($elems,)* json_internal!($shared, $last)])
};
(@array $shared:expr, [$($elems:expr),*] , $($rest:tt)*) => {
json_internal!(@array $shared, [$($elems,)*] $($rest)*)
};
(@array $shared:expr, [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
json_unexpected!($unexpected)
};
(@object $shared:expr, $object:ident () () ()) => {};
(@object $shared:expr, $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
let key: &str = ($($key)+).as_ref();
let pair = ($crate::Value::copy_str(key, $shared), $value);
let _ = $object.append_pair(pair);
json_internal!(@object $shared, $object () ($($rest)*) ($($rest)*));
};
(@object $shared:expr, $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
json_unexpected!($unexpected);
};
(@object $shared:expr, $object:ident [$($key:tt)+] ($value:expr)) => {
let key: &str = ($($key)+).as_ref();
let pair = ($crate::Value::copy_str(key, $shared), $value);
let _ = $object.append_pair(pair);
};
(@object $shared:expr, $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, null)) $($rest)*);
};
(@object $shared:expr, $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => {
json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, true)) $($rest)*);
};
(@object $shared:expr, $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => {
json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, false)) $($rest)*);
};
(@object $shared:expr, $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, [$($array)*])) $($rest)*);
};
(@object $shared:expr, $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, {$($map)*})) $($rest)*);
};
(@object $shared:expr, $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, $value)) , $($rest)*);
};
(@object $shared:expr, $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
json_internal!(@object $shared, $object [$($key)+] (json_internal!($shared, $value)));
};
(@object $shared:expr, $object:ident ($($key:tt)+) (:) $copy:tt) => {
json_internal!();
};
(@object $shared:expr, $object:ident ($($key:tt)+) () $copy:tt) => {
json_internal!();
};
(@object $shared:expr, $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
json_unexpected!($colon);
};
(@object $shared:expr, $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
json_unexpected!($comma);
};
(@object $shared:expr, $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
json_internal!(@object $shared, $object ($key) (: $($rest)*) (: $($rest)*));
};
(@object $shared:expr, $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => {
json_expect_expr_comma!($($unexpected)+);
};
(@object $shared:expr, $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
json_internal!(@object $shared, $object ($($key)* $tt) ($($rest)*) ($($rest)*));
};
($shared:expr, true) => {
$crate::Value::new_bool(true, $shared)
};
($shared:expr, false) => {
$crate::Value::new_bool(false, $shared)
};
($shared:expr, null) => {
$crate::Value::new_null($shared)
};
($shared:expr, []) => {
$crate::Value::new_array($shared, 0)
};
($shared:expr, [ $($tt:tt)+ ]) => {
json_internal!(@array $shared, [] $($tt)+)
};
($shared:expr, {}) => {
$crate::Value::new_object($shared, 0)
};
($shared:expr, { $($tt:tt)+ }) => {
{
let mut obj_value = $crate::Value::new_object($shared, 0);
json_internal!(@object $shared, obj_value () ($($tt)+) ($($tt)+));
obj_value
}
};
($shared:expr, $other:expr) => {
$crate::value::to_value_in($shared.into(), &$other).unwrap()
};
}
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! json_internal_array {
($shared:expr, $($content:tt)*) => {
{
let mut arr_value = $crate::Value::new_array($shared, 0);
$(
arr_value.append_value($content);
)*
arr_value
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! json_unexpected {
() => {};
}
#[macro_export]
#[doc(hidden)]
macro_rules! json_expect_expr_comma {
($e:expr , $($tt:tt)*) => {};
}
#[cfg(test)]
mod test {
use std::collections::HashMap;
use crate::value::value_trait::JsonValueTrait;
#[test]
fn test_json_memory() {
assert!(json!(true).is_static());
assert!(json!(false).is_static());
assert!(json!(null).is_static());
assert!(json!([]).is_static());
assert!(json!({}).is_static());
assert!(json!(123).is_static());
assert!(json!(1.23).is_static());
assert!(json!("123").is_root());
assert!(json!("").is_root());
assert!(json!({"1": 123}).is_root());
assert!(json!([[[]]]).is_root());
}
#[test]
fn test_json_macro() {
assert!(json!(true).is_true());
assert!(json!(false).is_false());
assert!(json!(null).is_null());
assert!(json!("123").is_str());
assert!(json!(vec![1]).is_array());
assert_eq!(json!(vec![1, 2, 3][2]).as_i64(), Some(3));
let buf = json!([1, 2, 3]);
let arr = json!([true, false, null, 1, 2, 3, "hi", 1 == 2, buf[1] == buf[2]]);
assert!(arr.is_array());
assert!(arr[arr.len() - 1].is_false());
let key = "i";
let key2 = "\"i\"";
let obj = json!({
"a": true,
"b": false,
"c": null,
"array": vec![1, 2, 3],
"map": ({
let mut map = HashMap::<String, String>::new();
map.insert("a".to_string(), "b".to_string());
map
}),
"f": 2.333,
"g": "hi",
"h": 1 == 2,
key: {
key2: [buf[1] == buf[2], 1],
},
});
assert!(obj.is_object());
assert!(obj["a"].is_true());
assert!(obj["array"][0].as_u64().unwrap() == 1);
assert!(obj["map"]["a"].as_str().unwrap() == "b");
assert!(obj[key][key2][1].as_u64().unwrap() == 1);
let obj = json!({
"a": { "b" : {"c": [[[]], {}, {}]} }
});
assert!(obj["a"]["b"]["c"][0][0].is_array());
}
#[test]
fn test_array_macro() {
let arr = array![];
assert!(arr.into_value().is_static());
let arr = array![true, false, null, 1, 2, 3, "hi", 1 == 2];
assert!(arr[arr.len() - 1].is_false());
let buf = array![1, 2, 3];
let arr = array![true, false, null, 1, 2, 3, "hi", 1 == 2, buf[1] == buf[2]];
assert!(arr[arr.len() - 1].is_false());
}
#[test]
fn test_object_macro() {
let obj = object! {};
assert!(obj.into_value().is_static());
let obj = object! {
"a": true,
"b": false,
"c": null,
"d": 1,
"e": 2,
"f": 3,
"g": "hi",
"h": 1 == 2,
};
assert!(obj["a"].is_true());
let buf = array![1, 2, 3];
let obj = object! {
"a": true,
"b": false,
"c": null,
"d": 1,
"e": 2,
"f": 3,
"g": "hi",
"h": 1 == 2,
"i": {
"i": [buf[1] == buf[2], 1],
},
};
assert!(obj["i"]["i"][1].as_u64().unwrap() == 1);
}
}