macro_rules! n_key_list {
{
$(#[$meta:meta])*
$vis:vis struct $mapname:ident $(<$($P:ident),*>)? for $V:ty
$( where [ $($constr:tt)+ ] )?
{
$($body:tt)+
}
} => { ... };
{
$(#[$meta:meta])*
$vis:vis struct [$($($G:tt)+)?] $mapname:ident [$($($P:tt)+)?] for $V:ty
$( [ where $($constr:tt)+ ])?
{
$( $(( $($flag:ident)+ ))? $key:ident : $KEY:ty $({ $($source:tt)+ })? ),+
$(,)?
}
} => { ... };
{ @access($ex:expr, (Option) $key:ident : $t:ty ) } => { ... };
{ @access($ex:expr, () $key:ident : $t:ty) } => { ... };
{ @access($ex:expr, (Option) $key:ident : $t:ty { . $field:tt } ) } => { ... };
{ @access($ex:expr, () $key:ident : $t:ty { . $field:tt } ) } => { ... };
{ @access($ex:expr, (Option) $key:ident : $t:ty { $func:ident () } ) } => { ... };
{ @access($ex:expr, () $key:ident : $t:ty { $func:ident () } ) } => { ... };
}
Expand description
Declare a structure that can hold elements with multiple unique keys.
Each element can be looked up by any of its keys. The keys themselves can be any type that
supports Hash
, Eq
, and Clone
. Elements can have multiple keys of the same type: for
example, a person can have a username String
and an irc_handle String
.
Multiple values can be stored for a given key: a lookup of one key returns all elements with that key.
Keys may be accessed from elements either by field access or by an accessor function.
Keys may be optional. If all keys are optional, then we require additionally that every element must have at least one key.
§Examples
use tor_basic_utils::n_key_list;
// We declare a person struct with several different fields.
pub struct Person {
username: String,
irc_handle: String,
student_id: Option<u64>,
favorite_joke: Option<String>,
}
n_key_list! {
pub struct PersonList for Person {
// See note on "Key syntax" below. The ".foo" syntax
// here means that the value for the key is returned
// by accessing a given field.
username: String { .username },
irc_handle: String { .irc_handle },
(Option) student_id: u64 { .student_id }
}
}
let mut people = PersonList::new();
people.insert(Person {
username: "mina".into(),
irc_handle: "pashMina".into(),
student_id: None,
favorite_joke: None,
});
assert_eq!(people.by_username("mina").len(), 1);
assert_eq!(people.by_irc_handle("pashMina").len(), 1);
§Key syntax
You can tell the map to access the keys of an element in any of several ways.
name : type { func() }
- A key whose name isname
and type istype
, that can be accessed from a given element by callingelement.func()
.name : type { .field }
- A key whose name isname
and type istype
, that can be accessed from a given element by calling&element.field
.name : type
- Short for asname : type { name() }
.
If a key declaration is preceded with (Option)
, then the key is treated as optional, and
accessor functions are expected to return Option<&Type>
.
§Additional features
You can put generic parameters and where
constraints on your structure. The where
clause (if
present) must be wrapped in square brackets.
If you need to use const generics or lifetimes in your structure, you need to use square brackets instead of angle brackets, and specify both the generic parameters and the type that you are implementing. (This is due to limitations in the Rust macro system.) For example:
n_key_list!{
struct['a, T, const N: usize] ArrayMap2['a, T, N] for (String, [&'a T;N])
[ where T: Clone + 'a ]
{
name: String { .0 }
}
}