derive_delegate!() { /* proc-macro */ }Expand description
Derive filler: Delegate functions to each of the fields in the struct.
§Semantics
Trait functions are implemented by calling the same function on each struct field in the order specified in the struct definition.
§Parameters
Parameters are passed as-is into each field delegation call.
Hence, all parameters must implement Copy or be a reference.
If the parameter type is Self/&Self/&mut Self,
the corresponding field is passed to the delegation call instead.
§Return values
If the return type is (), no return values are involved.
If the return type is Self, a new Self is constructed,
with each field as the result of the delegation call for that field.
For all other return types, the function should use the attribute
#[portrait(derive_delegate(reduce = reduce_fn))]reduce_fn(a, b) is called to reduce the return value of every two fields to the output.
reduce_fn may be a generic function that yields different inputs and outputs,
provided that the final reduction call returns the type requested by the trait.
§Options
The #[portrait(derive_delegate(...))] attribute can be applied on associated functions
to configure the derived delegation for the function.
§try
If the try option is applied, the return type must be in the form R<T, ...>,
e.g. Result<T, Error>, Option<T>, etc., where the type implements Try.
Each delegation gets an ? operator to return the error branch,
and the result is wrapped by an Ok(...) call.
Ok can be overridden by providing a value to the try option, e.g.
#[portrait(derive_delegate(try = Some))]
fn take(&self) -> Option<i32>;§reduce, reduce_base
If the reduce option is applied,
the return values of delegation calls are combined by the reducer.
The option requires a value that resolves to
a function that accepts two parameters and returns a value.
The type of the reducer is not fixed;
the types of parameters and return values are resolved separately.
If a reduce_base is supplied, the reducer starts with the base expression.
Otherwise, it starts with the first two values.
Example use cases include:
/// Returns the logical conjunction of all fields.
#[portrait(derive_delegate(reduce = |a, b| a && b))]
fn all(&self) -> bool;
/// Returns the sum of all field counts plus one.
#[portrait(derive_delegate(reduce = |a, b| a + b, reduce_base = 1))]
fn count(&self) -> usize;§either
If the either option is applied, when deriving from enums,
each match arm is wrapped with a nested tree of Either::Left(..)/Either::Right(..)s
such that each arm bijects to a unique variant of some Either<Either<Either<..>>>.
This is useful for delegating to separate enum implementations
when the return type is opaque (e.g. return-impl-trait).
#[portrait(derive_delegate(enum_either))]
fn iter(&self) -> impl Iterator<Item = Xxx>;Note that portrait only knows how to implement the trait with this associated function,
but does not derive anything for the trait bound Trait in -> impl Trait.
In particular, this means that someone has to have implemented Trait for Either<A, B>.
For traits not implemented by Either by default, an alternative wrapper could be used
by specifying the “left” and “right” operands in the attribute:
#[portrait(derive_delegate(enum_either = left_wrapper, right_wrapper))]
fn as_trait(&self) -> impl Trait;§Example
#[portrait::make]
trait Foo {
fn new(arg1: i32, arg2: &str, arg3: &mut i64) -> Self;
fn print(&self);
fn clone(&self) -> Self;
#[portrait(derive_delegate(reduce = |a, b| a && b))]
fn eq(&self, other: &Self) -> bool;
}
impl Foo for i32 {}
impl Foo for String {}
#[portrait::derive(Foo with portrait::derive_delegate)]
struct Fields {
a: i32,
b: String,
}Enums are also supported with a few restrictions:
- All associated functions must have a receiver.
- Non-receiver parameters must not take a
Self-based type.
#[portrait::make]
trait Foo {
fn print(&self);
fn clone(&self) -> Self;
}
impl Foo for i32 {}
impl Foo for String {}
#[portrait::derive(Foo with portrait::derive_delegate)]
enum Variants {
Foo { a: i32, b: String },
Bar(i32, String),
}Traits are implemented for generic types as long as the implementation is feasible, unlike the standard macros that implement on the generic variables directly.
#[portrait::make]
trait Create {
fn create() -> Self;
}
impl<T> Create for Vec<T> {
fn create() -> Self { vec![] }
}
#[portrait::derive(Create with portrait::derive_delegate)]
struct Fields<T> {
v: Vec<T>,
}
static_assertions::assert_impl_all!(Fields<i32>: Create);
static_assertions::assert_not_impl_any!(i32: Create);