Okay, this is a long one.
Each time you invoke a macro such as:
macro_rules! foo {
() => {
static FOO: usize = 0;
}
}
It creates a new static. It may not necessarily be nameable, but it’s a static.
mlfns take it a step further and, because they’re like macros, allow you to do:
macro fn foo<T>(t: &T) {
static FOO: Something<T> = things and stuff;
}
foo(thing);
where with normal macros you’d have to be a lot more verbose:
macro_rules! foo {
($t:ty, $e:expr) => {
static FOO: Something<T> = things and stuff;
}
}
foo!(Vec<Type<Result<Whatever<Thing>, MyError>>>, thing)
finally, for extracting and processing supertraits at compile-time, we’d need a way to combine this whole thing with some sort of type that can carry an arbitrary number of types into another type. it’s not a tuple, but some sort of variadic type that’s only useful for the type system. idk.
this is useful with monomorphization:
macro fn post<T: Event + ?Sized>(event: &mut T) -> bool {
macro fn get_targets_supertraits<T*: Event + ?Sized, U: T*, (V, ..): T>() -> Vec<(i32, Fn(&mut T))> { // not the actual signature btw but I don't feel like writing it all out
// recursive stuff until T is empty
}
// etc
}
uh I can’t explain this in simple words, but it basically unrolls to something like:
let hooks_1 = get_hooks<Type>();
let hooks_2 = get_hooks<dyn SuperTrait>();
let hooks_3 = get_hooks<dyn Event>();
// find lowest priority hook amongst the 3 hook lists and call it
while let Some(hook) = [&mut hooks_1, &mut hooks_2, &mut hooks_3].find_smallest_by(|x| x.peek().map(|x| x.priority).unwrap_or(i32::min())).flat_map(|x| x.next()).next() {
(hook.hook)(event);
}