#[macro_export]
macro_rules! scopes {
($($key:expr),*) => {{
let mut container = ::std::collections::HashSet::new();
$(
container.insert($key.to_owned());
)*
container
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! replace_expr {
($_t:tt $sub:expr) => {
$sub
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! count_items {
($($item:expr),*) => {<[()]>::len(&[$($crate::replace_expr!($item ())),*])};
}
#[doc(hidden)]
#[macro_export]
macro_rules! internal_build_map {
(/* required */, $map:ident, $key:expr, $val:expr) => {
$map.insert($key, $val);
};
(optional, $map:ident, $key:expr, $val:expr) => {
if let Some(val) = $val {
$map.insert($key, val);
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! build_map {
(
$(
$( $kind:ident )? $key:literal : $val:expr
),+ $(,)?
) => {{
let mut params = ::std::collections::HashMap::<&str, &str>::with_capacity(
$crate::count_items!($( $key ),*)
);
$(
$crate::internal_build_map!(
$( $kind )?,
params,
$key,
$val
);
)+
params
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! internal_build_json {
(/* required */, $map:ident, $key:expr, $val:expr) => {
$map.insert($key.to_string(), json!($val));
};
(optional, $map:ident, $key:expr, $val:expr) => {
if let Some(val) = $val {
$map.insert($key.to_string(), json!(val));
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! build_json {
(
$(
$( $kind:ident )? $key:literal : $val:expr
),+ $(,)?
) => {{
let mut params = ::serde_json::map::Map::with_capacity(
$crate::count_items!($( $key ),*)
);
$(
$crate::internal_build_json!(
$( $kind )?,
params,
$key,
$val
);
)+
::serde_json::Value::from(params)
}};
}
#[cfg(test)]
mod test {
use crate::{build_json, build_map, scopes};
use serde_json::{json, Map, Value};
use std::collections::HashMap;
#[test]
fn test_hashset() {
let scopes = scopes!("hello", "world", "foo", "bar");
assert_eq!(scopes.len(), 4);
assert!(scopes.contains("hello"));
assert!(scopes.contains("world"));
assert!(scopes.contains("foo"));
assert!(scopes.contains("bar"));
}
#[test]
fn test_build_map() {
let id = "Pink Lemonade";
let artist = Some("The Wombats");
let market: Option<i32> = None;
let market_str = market.map(|x| x.to_string());
let with_macro = build_map! {
"id": id,
optional "artist": artist,
optional "market": market_str.as_deref(),
};
let mut manually = HashMap::<&str, &str>::with_capacity(3);
manually.insert("id", id);
let market_str = market.map(|x| x.to_string());
if let Some(val) = artist {
manually.insert("artist", val);
}
if let Some(val) = market_str.as_deref() {
manually.insert("market", val);
}
assert_eq!(with_macro, manually);
}
#[test]
fn test_json_query() {
let id = "Pink Lemonade";
let artist = Some("The Wombats");
let market: Option<i32> = None;
let with_macro = build_json! {
"id": id,
optional "artist": artist,
optional "market": market.map(|x| x.to_string()),
};
let mut manually = Map::with_capacity(3);
manually.insert("id".to_string(), json!(id));
if let Some(val) = artist.map(|x| json!(x)) {
manually.insert("artist".to_string(), val);
}
if let Some(val) = market.map(|x| x.to_string()).map(|x| json!(x)) {
manually.insert("market".to_string(), val);
}
assert_eq!(with_macro, Value::from(manually));
}
}