#[macro_export(local_inner_macros)]
macro_rules! value {
($($tt:tt)*) => {
value_internal!($($tt)*)
};
}
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! value_internal {
(@unnamed [$($e:expr, )*] ()) => { vec_wrapper![$($e, )*] };
(@unnamed [$($e:expr, )*] (($($array:tt)*) $($rest:tt)*)) => {
value_internal!(@unnamed [$($e, )*] (value_internal!(($($array)*))) $($rest)*)
};
(@unnamed [$($e:expr, )*] ($variant:ident ($($array:tt)*) $($rest:tt)*)) => {
value_internal!(@unnamed [$($e, )*] (value_internal!($variant ($($array)*))) $($rest)*)
};
(@unnamed [$($e:expr, )*] ({$($map:tt)*} $($rest:tt)*)) => {
value_internal!(@unnamed [$($e, )*] (value_internal!({$($map)*})) $($rest)*)
};
(@unnamed [$($e:expr, )*] ($variant:ident {$($map:tt)*} $($rest:tt)*)) => {
value_internal!(@unnamed [$($e, )*] (value_internal!($variant {$($map)*})) $($rest)*)
};
(@unnamed [$($e:expr, )*] ($value:expr) , $($rest:tt)*) => {
value_internal!(@unnamed [$($e, )* $value , ] ($($rest)*))
};
(@unnamed [$($e:expr, )*] ($value:expr) $unexpected:tt $($rest:tt)*) => {
let token = core::stringify!($unexpected);
compile_error!("unexpected token after expression: {}", token);
};
(@unnamed [$($e:expr, )*] ($value:expr)) => {
vec_wrapper![ $($e, )* value_internal!($value) ]
};
(@unnamed [$($e:expr, )*] ($value:expr , $($rest:tt)*)) => {
value_internal!(@unnamed [$($e, )*] (value_internal!($value)) , $($rest)*)
};
(@named [$(($k:expr, $v:expr), )*] () ()) => { vec_wrapper![ $(($k, $v), )* ] };
(@named [$(($k:expr, $v:expr), )*] [$key:expr] ($value:expr) , $($rest:tt)*) => {
{
let field_name = literal_aware_stringify!($key);
value_internal!(@named [$(($k, $v), )* (field_name, $value), ] () ($($rest)*))
}
};
(@named [$(($k:expr, $v:expr), )*] [$key:expr] ($value:expr) $unexpected:tt $($rest:tt)*) => {
let token = core::stringify!($unexpected);
compile_error!("unexpected token after expression: {}", token);
};
(@named [$(($k:expr, $v:expr), )*] [$key:expr] ($value:expr)) => {
{
let field_name = literal_aware_stringify!($key);
vec_wrapper![ $(($k, $v), )* (field_name, $value) ]
}
};
(@named [$(($k:expr, $v:expr), )*] ($key:expr) (: ($($array:tt)*) $($rest:tt)*)) => {
value_internal!(@named [$(($k, $v), )*] [$key] (value_internal!(($($array)*))) $($rest)*)
};
(@named [$(($k:expr, $v:expr), )*] ($key:expr) (: $variant:ident ($($array:tt)*) $($rest:tt)*)) => {
value_internal!(@named [$(($k, $v), )*] [$key] (value_internal!($variant ($($array)*))) $($rest)*)
};
(@named [$(($k:expr, $v:expr), )*] ($key:expr) (: {$($map:tt)*} $($rest:tt)*)) => {
value_internal!(@named [$(($k, $v), )*] [$key] (value_internal!({$($map)*})) $($rest)*)
};
(@named [$(($k:expr, $v:expr), )*] ($key:expr) (: $variant:ident {$($map:tt)*} $($rest:tt)*)) => {
value_internal!(@named [$(($k, $v), )*] [$key] (value_internal!($variant {$($map)*})) $($rest)*)
};
(@named [$(($k:expr, $v:expr), )*] ($key:expr) (: $value:expr , $($rest:tt)*)) => {
value_internal!(@named [$(($k, $v), )*] [$key] (value_internal!($value)) , $($rest)*)
};
(@named [$(($k:expr, $v:expr), )*] ($key:expr) (: $value:expr)) => {
value_internal!(@named [$(($k, $v), )*] [$key] (value_internal!($value)))
};
(@named [$(($k:expr, $v:expr), )*] ($key:expr) (:)) => {
compile_error!("missing value for last entry");
};
(@named [$(($k:expr, $v:expr), )*] ($key:expr) ()) => {
compile_error!("missing colon and value for last entry");
};
(@named [$(($k:expr, $v:expr), )*] () (: $($rest:tt)*)) => {
compile_error!("colon in wrong position");
};
(@named [$(($k:expr, $v:expr), )*] ($($key:tt)*) (, $($rest:tt)*)) => {
compile_error!("comma in key of named composite");
};
(@named [$(($k:expr, $v:expr), )*] () (($key:expr) : $($rest:tt)*)) => {
value_internal!(@named [$(($k, $v), )*] ($key) (: $($rest)*))
};
(@named [$(($k:expr, $v:expr), )*] ($($key:tt)*) ($tt:tt $($rest:tt)*)) => {
value_internal!(@named [$(($k, $v), )*] ($($key)* $tt) ($($rest)*))
};
() => {
$crate::Value::unnamed_composite(Vec::<$crate::Value>::new())
};
(()) => {
$crate::Value::unnamed_composite(Vec::<$crate::Value>::new())
};
({}) => {
$crate::Value::named_composite(Vec::<(String, $crate::Value)>::new())
};
({ $($tt:tt)* }) => {
{
let fields: Vec::<(String, $crate::Value)> = value_internal!(@named [] () ($($tt)*));
$crate::Value::named_composite(fields)
}
};
($variant:ident { $($tt:tt)* }) => {
{
let variant_name = literal_aware_stringify!($variant);
let fields: Vec::<(String, $crate::Value)> = value_internal!(@named [] () ($($tt)*));
$crate::Value::named_variant(variant_name,fields)
}
};
(( $($tt:tt)* )) => {
{
let fields = value_internal!(@unnamed [] ($($tt)*));
$crate::Value::unnamed_composite(fields)
}
};
($variant:ident ( $($tt:tt)* )) => {
{
let variant_name = literal_aware_stringify!($variant);
let fields = value_internal!(@unnamed [] ($($tt)*));
$crate::Value::unnamed_variant(variant_name,fields)
}
};
($val:expr) => {
$crate::Value::from($val)
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! vec_wrapper {
($($content:tt)*) => {
vec![$($content)*]
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! literal_aware_stringify {
($tt:literal) => {
$tt.to_string()
};
($($tt:tt)*) => {
stringify!($($tt)*).to_string()
};
}
#[cfg(test)]
#[macro_use]
mod test {
use crate::prelude::*;
use crate::{value, Value};
#[test]
fn macro_tests() {
assert_eq!(value!(1), Value::from(1));
assert_eq!(value!(-122193223i64), Value::from(-122193223i64));
assert_eq!(value!(89usize), Value::from(89usize));
assert_eq!(value!(false), Value::from(false));
assert_eq!(value!(true), Value::from(true));
assert_eq!(value!('h'), Value::from('h'));
assert_eq!(value!("Hello"), Value::from("Hello"));
assert_eq!(value!("Hello".to_string()), Value::from("Hello"));
let s = "Hello".to_string();
assert_eq!(value!(s), Value::from("Hello"));
let unnamed_composite =
Value::unnamed_composite([Value::from(1), Value::from("nice"), Value::from('t')]);
assert_eq!(value!((1, "nice", 't')), unnamed_composite);
assert_eq!(value!((1, "nice", 't',)), unnamed_composite);
let empty_composite = Value::unnamed_composite([]);
assert_eq!(value!(()), empty_composite);
let named_composite =
Value::named_composite([("num", Value::from(3)), ("item", Value::from("tea"))]);
assert_eq!(value!({num: 3, item: "tea"}), named_composite);
assert_eq!(value!({num: 3, item: "tea", }), named_composite);
let variant_no_fields = Value::variant("v1", crate::Composite::Unnamed(vec![]));
assert_eq!(value!(v1()), variant_no_fields);
let named_variant = Value::variant(
"V2",
crate::Composite::named([("num", Value::from(3)), ("item", Value::from("tea"))]),
);
assert_eq!(value!(V2 { num: 3, item: "tea" }), named_variant);
let value = value!({ "string key": 123 });
assert_eq!(value, Value::named_composite([("string key", Value::from(123))]));
let _ = value!({ unnamed: unnamed_composite, vals: (v1{name: "berry", age: 34}, named_variant), named: named_composite });
}
}