#[entrait]
Expand description
The entrait attribute macro, used to generate traits and delegating implementations of them.
For functions
When used with a function, the macro must be given the name of a trait to generate. The macro will generate that trait, and connect it to the function by supplying an implementation for Impl, plus optional mock implementations.
Syntax
#[entrait($visibility? $TraitIdent)]
fn ...
$visibility
: Optional visibility specifier for the generated trait. See the Rust documentation for valid values.$TraitIdent
: Any valid Rust identifier that starts with an upper-case character, used as the name of the new trait.
with options:
#[entrait($visibility? $TraitIdent, $option, ...)]
fn ...
For modules
Using the attribute on a module is used to group several non-private functions into one trait. Only non-private functions are considered by the macro.
Syntax
#[entrait($visibility? $TraitIdent)]
mod some_module {
pub fn ...
}
For traits
When used with a trait, the macro will only provide a delegating implementation for Impl that delegates to another trait implementation. It can also optionally generate mock impls of the trait.
There are mainly two delegation modes:
- Specify a trait name to use as delegation target, resulting in an internal dependency.
- Don’t specify a trait name, resulting in a leaf dependency which has to delegate using the same trait, but for a different type.
When mocking is enabled, exporting the mocks is implicitly turned on (i.e. not gated by #[cfg(test)]
).
Syntax
#[entrait($visibility? $TraitIdent?)]
trait ...
with options:
#[entrait($visibility? $TraitIdent?, $option, ...)]
trait ...
Example 1
Internal dependency, static dispatch (delegation bound: T: DelegateFoo<T>
):
#[entrait(FooImpl, delegate_by = DelegateFoo)]
trait Foo {}
Note: The associated type DelegateFoo<T>::Target
must implement FooImpl<T>
.
Example 2
Leaf dependency, static dispatch (delegation bound: T: Foo
):
#[entrait]
trait Foo {}
Example 3
Leaf dependency, dynamic dispatch (delegation bound: T: Borrow<dyn Foo>
):
#[entrait(delegate_by = Borrow)]
trait Foo {}
For impl blocks
When used on an impl block, the macro will generate a delegating implementation for a delegation trait “TraitImpl
” generated with #[entrait(TraitImpl)] trait Trait {}
.
The impl block must be be a trait implementation, not an inherent implementation.
Within this block, only static methods with a dependency receiver are supported.
These methods must correspond with the method definitions from the trait that is implemented.
I.e. the method signatures have to match, except for self
receivers which must be replaced by dependency receivers.
The macro will convert the impl block from a trait implementation to an inherent implementation block, and additionally generate a proper trait implementation block based on the methods present.
Given the trait declaration:
#[entrait(TraitImpl, delegate_by = DelegateTrait)]
trait Trait {
fn foo(&self, arg: i32) -> i32;
}
The delegation chain is fulfilled with a block like the following:
pub struct MyType;
#[entrait]
impl TraitImpl for MyType {
fn foo(_deps: &impl std::any::Any, arg: i32) -> i32 {
arg * 2
}
}
struct App;
// The type `MyType` may now be used as a delegation target:
impl DelegateTrait<Self> for App {
type Target = MyType;
}
assert_eq!(42, Impl::new(App).foo(21));
Borrow
delegation and dyn
:
The only attribute parameter currently supported on impl blocks is adding the dyn
keyword, to indicate that the delegation strategy uses dynamic dispatch:
#[entrait(TraitImpl, delegate_by = Borrow)]
trait Trait {
fn foo(&self, arg: i32) -> i32;
}
struct MyType;
#[entrait(dyn)]
impl TraitImpl for MyType {
fn foo(_deps: &impl std::any::Any, arg: i32) -> i32 {
arg * 2
}
}
Syntax
#[entrait(dyn?)]
impl TraitPath for Type {
...
}
Options
An option can be just $option
or $option = $value
. An option without value means true
.
Option | Type | Target | Default | Description |
---|---|---|---|---|
no_deps | bool | fn | false | Disables the dependency parameter, so that the first parameter is just interpreted as a normal function parameter. Useful for reducing noise in some situations. |
export | bool | fn +mod | false | If mocks are generated, exports these mocks even in release builds. Only relevant for libraries. |
unimock | bool | fn +mod +trait | false 1 | Used to turn off unimock implementation when the unimock feature is enabled. |
mockall | bool | fn +mod +trait | false | Enable mockall mocks. |
box_future | bool | fn +mod +trait | false 2 | In the case of an async fn , use the async_trait macro on the resulting trait. Requires the boxed-futures entrait feature. |
associated_future | bool | fn +mod +trait | false 3 | In the case of an async fn , use an associated future to avoid heap allocation. Currently requires a nighlty Rust compiler, with feature(type_alias_impl_trait) . |
delegate_by | Self /Borrow /custom ident | trait | Self | Controls the generated Impl<T> delegation of this trait. Self generates a T: Trait bound. Borrow generates a T: Borrow<dyn Trait> bound. Any other value generates a new trait with that name which controls the delegation. |