macro_rules! closure_trait {
($($input:tt)*) => { ... };
}Expand description
Declares a trait for an Fn-, FnMut-, or FnOnce-like closure.
§Quick guide
Declare zero or more named parameters and an optional output:
closure_trait!(Trait<T: Bounds>(left: T, right: T) -> Output);
closure_trait!(Trait(first: Input, second: Input) -> Output);Put &self, &mut self, or self before the arguments to select Fn,
FnMut, or FnOnce behavior. Omitting the receiver means &self; omitting the output
means (). Documentation comments and visibility such as pub may precede
the trait name. Other trait attributes are not supported. Expansion-controlling
attributes such as #[cfg(...)] may precede the macro invocation; ordinary
item attributes placed there do not propagate to the generated trait. Use the
resulting trait name and matching signature with closure!.
A signature containing <T: Bounds> generates generic call methods, so one
value can be called with every argument type satisfying those bounds. Without
a type parameter, the call methods are object-safe. The receiver selects the
closure kind:
- an omitted receiver, or
&self, generatescall,call_mut, andcall_once; &mut selfgeneratescall_mutandcall_once;selfgeneratescall_once.
Fn- and FnMut-like traits provide their less restrictive call methods by
forwarding to the required method. With the default alloc feature, every
trait also has call_box, allowing a non-generic FnOnce-like trait to be
called through Box<dyn Trait>.
use generic_closure::{closure, closure_trait};
use std::fmt::Display;
closure_trait!(
/// Returns the display width of a value.
pub DisplayLength<T: Display>(value: T) -> usize
);
fn invoke_twice(f: &impl DisplayLength) {
assert_eq!(f.call(123), 3);
assert_eq!(f.call("hello"), 5);
}
let display_length = closure!(
DisplayLength<T: Display>(value: T) -> usize { value.to_string().len() }
);
invoke_twice(&display_length);A non-generic closure trait can erase unrelated bodies behind dyn Trait:
use generic_closure::{closure, closure_trait};
closure_trait!(Render(value: i32) -> String);
let render = closure!(
Render(value: i32) -> String { format!("value={value}") }
);
let render: Box<dyn Render> = Box::new(render);
assert_eq!(render.call(42), "value=42");When the either feature is enabled, every generated trait is also
implemented recursively for either::Either<L, R> whenever both L and R
implement it.
§Syntax diagnostics
Generic declarations require one type parameter with at least one bound.
Arguments use name: Type syntax and may be omitted or repeated; a trailing
comma is accepted. Generic signatures may append a Rust-like where clause
for predicates that are not bounds directly on the type parameter. Self
cannot appear in argument types, the output type, generic bounds, or where
predicates. Omitting -> Output means -> ().