Macro n_key_set

Source
macro_rules! n_key_set {
    {
    $(#[$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 or removed 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.

All keys in the set must be unique: if a new element is inserted that has the same value for any key as a previous element, the old element is removed.

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_set;

// 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_set! {
    pub struct PersonSet 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 = PersonSet::new();
people.insert(Person {
    username: "mina".into(),
    irc_handle: "pashMina".into(),
    student_id: None,
    favorite_joke: None
});
assert!(people.by_username("mina").is_some());
assert!(people.by_irc_handle("pashMina").is_some());

§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 is name and type is type, that can be accessed from a given element by calling element.func().
  • name : type { .field } - A key whose name is name and type is type, that can be accessed from a given element by calling &element.field.
  • name : type - Short for as name : 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_set!{
    struct['a, T, const N: usize] ArrayMap2['a, T, N] for (String, [&'a T;N])
        [ where T: Clone + 'a ]
    {
         name: String { .0 }
    }
}