#[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: AsRef<dyn Foo>
):
#[entrait(delegate_by=ref)]
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));
§dyn trait
delegation with AsRef
:
The only attribute parameter currently supported on impl blocks is adding the ref
keyword, to indicate that the delegation strategy uses dynamic dispatch through AsRef
:
#[entrait(TraitImpl, delegate_by=ref)]
trait Trait {
fn foo(&self, arg: i32) -> i32;
}
struct MyType;
#[entrait(ref)]
impl TraitImpl for MyType {
fn foo(_deps: &impl std::any::Any, arg: i32) -> i32 {
arg * 2
}
}
§Syntax
#[entrait(ref?)]
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. |
mock_api | ident | fn +mod +trait | The identifier to use for mock APIs (for libraries that support custom identifiers. The unimock library requires this to be explicitly specified. | |
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. |
delegate_by | Self /ref /custom ident | trait | Self | Controls the generated Impl<T> delegation of this trait. Self generates a T: Trait bound. ref generates a T: AsRef<dyn Trait> bound. Borrow is deprecated and uses the core::borrow::Borrow trait. Any other value generates a new trait with that name which controls the delegation. |
?Send | true | fn +mod +trait | false | Opts out of Send bounds for Future outputs from async functions in generated traits. |
Enabled by default by turning on the
unimock
cargo feature. ↩