Attribute Macro entrait::entrait

source ·
#[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:

  1. Specify a trait name to use as delegation target, resulting in an internal dependency.
  2. 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 traitTraitImpl” 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.

OptionTypeTargetDefaultDescription
no_depsboolfnfalseDisables the dependency parameter, so that the first parameter is just interpreted as a normal function parameter. Useful for reducing noise in some situations.
exportboolfn+modfalseIf mocks are generated, exports these mocks even in release builds. Only relevant for libraries.
mock_apiidentfn+mod+traitThe identifier to use for mock APIs (for libraries that support custom identifiers. The unimock library requires this to be explicitly specified.
unimockboolfn+mod+traitfalse1Used to turn off unimock implementation when the unimock feature is enabled.
mockallboolfn+mod+traitfalseEnable mockall mocks.
delegate_bySelf/ref/custom identtraitSelfControls 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.
?Sendtruefn+mod+traitfalseOpts out of Send bounds for Future outputs from async functions in generated traits.

  1. Enabled by default by turning on the unimock cargo feature.