Skip to main content

closure_trait

Macro closure_trait 

Source
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, generates call, call_mut, and call_once;
  • &mut self generates call_mut and call_once;
  • self generates call_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 -> ().