#[macro_export(local_inner_macros)]
macro_rules! json {
(true) => {
$crate::Value::new_bool(true)
};
(false) => {
$crate::Value::new_bool(false)
};
(null) => {
$crate::Value::new_null()
};
([]) => {
$crate::Array::new().into_value()
};
({}) => {
$crate::Object::new().into_value()
};
($($json:tt)+) => {
json_internal!($($json)+)
};
}
#[macro_export(local_inner_macros)]
macro_rules! array {
() => {
$crate::value::Array::new()
};
($($tt:tt)+) => {
{
let value = json_internal!([$($tt)+]);
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 value = json_internal!({$($tt)+});
value.into_object().expect("the literal is not a json object")
}
};
}
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! json_internal {
(@array [$($elems:expr,)*]) => {
json_internal_array![$($elems)*]
};
(@array [$($elems:expr),*]) => {
json_internal_array![$($elems)*]
};
(@array [$($elems:expr,)*] null $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*)
};
(@array [$($elems:expr,)*] true $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*)
};
(@array [$($elems:expr,)*] false $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*)
};
(@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*)
};
(@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*)
};
(@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*)
};
(@array [$($elems:expr,)*] $last:expr) => {
json_internal!(@array [$($elems,)* json_internal!($last)])
};
(@array [$($elems:expr),*] , $($rest:tt)*) => {
json_internal!(@array [$($elems,)*] $($rest)*)
};
(@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
json_unexpected!($unexpected)
};
(@object $object:ident () () ()) => {};
(@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
let key: &str = ($($key)+).as_ref();
let pair = ($crate::Value::copy_str(key), $value);
let _ = $object.append_pair(pair);
json_internal!(@object $object () ($($rest)*) ($($rest)*));
};
(@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
json_unexpected!($unexpected);
};
(@object $object:ident [$($key:tt)+] ($value:expr)) => {
let key: &str = ($($key)+).as_ref();
let pair = ($crate::Value::copy_str(key), $value);
let _ = $object.append_pair(pair);
};
(@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*);
};
(@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*);
};
(@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*);
};
(@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*);
};
(@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*);
};
(@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*);
};
(@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
json_internal!(@object $object [$($key)+] (json_internal!($value)));
};
(@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
json_internal!();
};
(@object $object:ident ($($key:tt)+) () $copy:tt) => {
json_internal!();
};
(@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
json_unexpected!($colon);
};
(@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
json_unexpected!($comma);
};
(@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*));
};
(@object $object:ident ($($key:tt)*) (: $($unexpected:tt)+) $copy:tt) => {
json_expect_expr_comma!($($unexpected)+);
};
(@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*));
};
(true) => {
$crate::Value::new_bool(true)
};
(false) => {
$crate::Value::new_bool(false)
};
(null) => {
$crate::Value::new_null()
};
([]) => {
$crate::Value::new_array()
};
([ $($tt:tt)+ ]) => {
json_internal!(@array [] $($tt)+)
};
({}) => {
$crate::Value::new_object()
};
({ $($tt:tt)+ }) => {
{
let mut obj_value = $crate::Value::new_object_with(8);
json_internal!(@object obj_value () ($($tt)+) ($($tt)+));
obj_value
}
};
($other:expr) => {
$crate::value::to_value(&$other).unwrap()
};
}
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! json_internal_array {
($($content:tt)*) => {
{
let mut arr_value = $crate::Value::new_array_with(8);
$(
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_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![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! {
"a": true,
"b": false,
"c": null,
"d": 1,
"e": 2,
"f": 3,
"g": "hi",
"h": 1 == 2,
};
assert!(obj["a"].is_true());
let arr = 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": [arr[1] == arr[2], 1],
},
};
assert!(obj["i"]["i"][1].as_u64().unwrap() == 1);
}
}