tup!() { /* proc-macro */ }
Expand description
The whole point.
Produces a named tuple, a struct that can contain a set of named arguments. Each named tuple can be added together or even default to a value if it does not already exist.
There are two different macros the tup!
macro for defining an expression and the Tup!
macro for defining a type.
§tup as an expression
In it’s most basic form a tup!
is formed just like a struct instantiation.
let mut farm = tup!(horse: 4, chicken: 3, ants: 999_999_999);
assert_eq!(farm.horse, 4);
assert_eq!(farm.chicken, 3);
// Got some ant killer
farm.ants = 0;
assert_eq!(farm.ants, 0);
And just like it, tup!
can use pre-existing variables.
let kingfisher = true;
let eagle = false;
let nest = tup!(kingfisher, toucan: true, eagle);
assert_eq!(nest, tup!(kingfisher: true, eagle: false, toucan: true))
§Tup as a type
However in certain cases defining the type exactly is necessary.
let recipe: Tup!(eggs: u8, milk: &str, flour: f32) = tup!(milk: "500ml", eggs: 4, flour: 203.6);
let person = tup!(name: "Joe", blue_eyes: true);
face_recognizer(vec![person]);
fn face_recognizer(
people: Vec<Tup!(name: &'static str, blue_eyes: bool)>,
) -> Tup!(confidence: f64, name: &'static str) {
tup!(confidence: 0.3, name: "Joe")
}
The type macro is also used to specify defaults using the #[tup_default]
attribute and the TupInto
trait to change the type.
#[tup_default]
pub fn main() {
let result: Tup!(foo: i32 = 3, bar: Option<i32> = None) = match input {
true => tup!(foo: 4).into_tup(),
false => tup!(bar: Some(4)).into_tup(),
};
read(tup!().into_tup());
}
#[tup_default]
fn read(books: Tup!(names: &'static [&'static str] = &[], ETA: i32 = 0)) {
// Read
}
§Tup type
Each Tup!
call produces a Tup type, the type itself eagerly implements
Copy
, Clone
, Eq
, PartialEq
, Ord
, PartialOrd
, Hash
assuming all the types it contains implement them. (Ord/PartialOrd is in lexicographic
ordering and Ord/Eq cannot be implemented on types that use different defaults
so if this is the case just convert them to non-defaulted versions before using them).
As well as this a Default
and Debug
trait is always implemented.
assert_eq!(tup!(rooms: ["garden", "shed"]), tup!(rooms: ["garden", "shed"]));
let rooms = vec!["bathroom", "bedroom"];
let non_copy = tup!(rooms);
assert_eq!(non_copy, non_copy.clone());
let copy = tup!(cows: 4, bulls: 2);
drop(copy);
assert!(copy > tup!(cows: 5, bulls: 1));
// Will print tup { farmer: "Joe", married: true }
println!("{:?}", tup!( married: true, farmer: "Joe"));
Finally the Add
trait is implemented so that you can transform between
different tup types. If both sides contain a certain argument, precedence is given to the
right hand side.
let farm1 = tup!(roosters: 4, dragons: 7, dogs: 1);
let farm2 = tup!(hens: 56, dogs: 3);
let combined_farm = farm1 + farm2;
assert_eq!(combined_farm, tup!(roosters: 4, hens: 56, dragons: 7, dogs: 3));