#![warn(missing_docs)] #![warn(unused_results)] #![doc(html_root_url="https://docs.rs/maplit/1/")] //! Macros for container literals with specific type. //! //! ``` //! #[macro_use] extern crate maplit; //! //! # fn main() { //! let map = hashmap!{ //! "a" => 1, //! "b" => 2, //! }; //! # } //! ``` //! //! The **maplit** crate uses `=>` syntax to separate the key and value for the //! mapping macros. (It was not possible to use `:` as separator due to syntactic //! restrictions in regular `macro_rules!` macros.) //! //! Note that rust macros are flexible in which brackets you use for the invocation. //! You can use them as `hashmap!{}` or `hashmap![]` or `hashmap!()`. //! //! Generic container macros already exist elsewhere, so those are not provided //! here at the moment. #[macro_export(local_inner_macros)] /// Create a **HashMap** from a list of key-value pairs /// /// ## Example /// /// ``` /// #[macro_use] extern crate maplit; /// # fn main() { /// /// let map = hashmap!{ /// "a" => 1, /// "b" => 2, /// }; /// assert_eq!(map["a"], 1); /// assert_eq!(map["b"], 2); /// assert_eq!(map.get("c"), None); /// # } /// ``` macro_rules! hashmap { (@single $($x:tt)*) => (()); (@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*])); ($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) }; ($($key:expr => $value:expr),*) => { { let _cap = hashmap!(@count $($key),*); let mut _map = ::std::collections::HashMap::with_capacity(_cap); $( let _ = _map.insert($key, $value); )* _map } }; } /// Create a **HashSet** from a list of elements. /// /// ## Example /// /// ``` /// #[macro_use] extern crate maplit; /// # fn main() { /// /// let set = hashset!{"a", "b"}; /// assert!(set.contains("a")); /// assert!(set.contains("b")); /// assert!(!set.contains("c")); /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! hashset { (@single $($x:tt)*) => (()); (@count $($rest:expr),*) => (<[()]>::len(&[$(hashset!(@single $rest)),*])); ($($key:expr,)+) => { hashset!($($key),+) }; ($($key:expr),*) => { { let _cap = hashset!(@count $($key),*); let mut _set = ::std::collections::HashSet::with_capacity(_cap); $( let _ = _set.insert($key); )* _set } }; } #[macro_export(local_inner_macros)] /// Create a **BTreeMap** from a list of key-value pairs /// /// ## Example /// /// ``` /// #[macro_use] extern crate maplit; /// # fn main() { /// /// let map = btreemap!{ /// "a" => 1, /// "b" => 2, /// }; /// assert_eq!(map["a"], 1); /// assert_eq!(map["b"], 2); /// assert_eq!(map.get("c"), None); /// # } /// ``` macro_rules! btreemap { // trailing comma case ($($key:expr => $value:expr,)+) => (btreemap!($($key => $value),+)); ( $($key:expr => $value:expr),* ) => { { let mut _map = ::std::collections::BTreeMap::new(); $( let _ = _map.insert($key, $value); )* _map } }; } #[macro_export(local_inner_macros)] /// Create a **BTreeSet** from a list of elements. /// /// ## Example /// /// ``` /// #[macro_use] extern crate maplit; /// # fn main() { /// /// let set = btreeset!{"a", "b"}; /// assert!(set.contains("a")); /// assert!(set.contains("b")); /// assert!(!set.contains("c")); /// # } /// ``` macro_rules! btreeset { ($($key:expr,)+) => (btreeset!($($key),+)); ( $($key:expr),* ) => { { let mut _set = ::std::collections::BTreeSet::new(); $( _set.insert($key); )* _set } }; } /// Identity function. Used as the fallback for conversion. #[doc(hidden)] pub fn __id(t: T) -> T { t } /// Macro that converts the keys or key-value pairs passed to another maplit /// macro. The default conversion is to use the [`Into`] trait, if no /// custom conversion is passed. /// /// The syntax is: /// /// `convert_args!(` `keys=` *function* `,` `values=` *function* `,` /// *macro_name* `!(` [ *key* => *value* [, *key* => *value* ... ] ] `))` /// /// Here *macro_name* is any other maplit macro and either or both of the /// explicit `keys=` and `values=` parameters can be omitted. /// /// [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html /// /// **Note** To use `convert_args`, the macro that is being wrapped /// must itself be brought into the current scope with `#[macro_use]` or `use`. /// /// # Examples /// /// ``` /// #[macro_use] extern crate maplit; /// # fn main() { /// /// use std::collections::HashMap; /// use std::collections::BTreeSet; /// /// // a. Use the default conversion with the Into trait. /// // Here this converts both the key and value string literals to `String`, /// // but we need to specify the map type exactly! /// /// let map1: HashMap = convert_args!(hashmap!( /// "a" => "b", /// "c" => "d", /// )); /// /// // b. Specify an explicit custom conversion for the keys. If we don't specify /// // a conversion for the values, they are not converted at all. /// /// let map2 = convert_args!(keys=String::from, hashmap!( /// "a" => 1, /// "c" => 2, /// )); /// /// // Note: map2 is a HashMap, but we didn't need to specify the type /// let _: HashMap = map2; /// /// // c. convert_args! works with all the maplit macros -- and macros from other /// // crates that have the same "signature". /// // For example, btreeset and conversion from &str to Vec. /// /// let set: BTreeSet> = convert_args!(btreeset!( /// "a", "b", "c", "d", "a", "e", "f", /// )); /// assert_eq!(set.len(), 6); /// /// /// # } /// ``` #[macro_export(local_inner_macros)] macro_rules! convert_args { (keys=$kf:expr, $macro_name:ident !($($k:expr),* $(,)*)) => { $macro_name! { $(($kf)($k)),* } }; (keys=$kf:expr, values=$vf:expr, $macro_name:ident !($($k:expr),* $(,)*)) => { $macro_name! { $(($kf)($k)),* } }; (keys=$kf:expr, values=$vf:expr, $macro_name:ident !( $($k:expr => $v:expr),* $(,)*)) => { $macro_name! { $(($kf)($k) => ($vf)($v)),* } }; (keys=$kf:expr, $macro_name:ident !($($rest:tt)*)) => { convert_args! { keys=$kf, values=$crate::__id, $macro_name !( $($rest)* ) } }; (values=$vf:expr, $macro_name:ident !($($rest:tt)*)) => { convert_args! { keys=$crate::__id, values=$vf, $macro_name !( $($rest)* ) } }; ($macro_name:ident ! $($rest:tt)*) => { convert_args! { keys=::std::convert::Into::into, values=::std::convert::Into::into, $macro_name ! $($rest)* } }; } #[test] fn test_hashmap() { use std::collections::HashMap; use std::collections::HashSet; let names = hashmap!{ 1 => "one", 2 => "two", }; assert_eq!(names.len(), 2); assert_eq!(names[&1], "one"); assert_eq!(names[&2], "two"); assert_eq!(names.get(&3), None); let empty: HashMap = hashmap!{}; assert_eq!(empty.len(), 0); let _nested_compiles = hashmap!{ 1 => hashmap!{0 => 1 + 2,}, 2 => hashmap!{1 => 1,}, }; let _: HashMap = convert_args!(keys=String::from, hashmap!( "one" => 1, "two" => 2, )); let _: HashMap = convert_args!(keys=String::from, values=__id, hashmap!( "one" => 1, "two" => 2, )); let names: HashSet = convert_args!(hashset!( "one", "two", )); assert!(names.contains("one")); assert!(names.contains("two")); let lengths: HashSet = convert_args!(keys=str::len, hashset!( "one", "two", )); assert_eq!(lengths.len(), 1); let _no_trailing: HashSet = convert_args!(keys=str::len, hashset!( "one", "two" )); } #[test] fn test_btreemap() { use std::collections::BTreeMap; let names = btreemap!{ 1 => "one", 2 => "two", }; assert_eq!(names.len(), 2); assert_eq!(names[&1], "one"); assert_eq!(names[&2], "two"); assert_eq!(names.get(&3), None); let empty: BTreeMap = btreemap!{}; assert_eq!(empty.len(), 0); let _nested_compiles = btreemap!{ 1 => btreemap!{0 => 1 + 2,}, 2 => btreemap!{1 => 1,}, }; }