Skip to main content

autoimpl

Attribute Macro autoimpl 

Source
#[autoimpl]
Expand description

An alternative to the standard derive macro

This macro may be used:

§On type definitions

#[autoimpl] on type definitions functions similarly to #[derive]. The differences are as follows.

There is no implied bound on generic parameters. Instead, bounds must be specified explicitly, using syntax like where T: Clone. The special syntax where T: trait may be used where trait desugars to the target trait for each implementation. An example:

#[autoimpl(Clone, Debug where T: trait)]
struct Wrapper<T>(pub T);

§ignore

Traits like Debug may be implemented while ignore-ing some fields, for example:

#[autoimpl(Debug ignore self.f)]
struct PairWithFn<T> {
    x: f32,
    y: f32,
    f: fn(&T),
}

§using

Traits like Deref may be implemented by using a named field, for example:

#[autoimpl(Deref, DerefMut using self.1)]
struct AnnotatedWrapper<T>(String, T);

In the above example, Deref::Target will be implemented as T (the type of the field self.1). The Target type may instead be specified explicitly:

#[autoimpl(Deref<Target = T> using self.0)]
struct MyBoxingWrapper<T: ?Sized>(Box<T>);

§Supported traits

Pathignoreusingnotes
::core::borrow::Borrow<T>-borrow targetT is type of target field
::core::borrow::BorrowMut<T>-borrow targetT is type of target field
::core::clone::Cloneyes-ignored fields use Default::default()
::core::cmp::Eq*-*allowed with PartialEq
::core::cmp::Ordyes-
::core::cmp::PartialEqyes-
::core::cmp::PartialOrdyes-
::core::convert::AsRef<T>-ref targetT is type of target field
::core::convert::AsMut<T>-ref targetT is type of target field
::core::default::Default--impl_default is a more flexible alternative
::core::fmt::Debugyes-
::core::hash::Hashyes-
::core::marker::Copy*-*allowed with Clone
::core::ops::Deref-deref targetSee Deref::Target type below
::core::ops::DerefMut-deref target

Traits are matched using the path, as follows:

  • Only the last component, e.g. #[autoimpl(Clone)]
  • The full path with leading ::, e.g. #[autoimpl(::core::clone::Clone)]
  • The full path without leading ::, e.g. #[autoimpl(core::clone::Clone)]
  • The full path with/without leading ::, using std instead of core or alloc, e.g. #[autoimpl(std::clone::Clone)]

§Parameter syntax

ParamsMulti :
   ( Trait ),+ Using? Ignores? WhereClause?

Using :
   using self . Member

Ignores :
   ignore ( self . Member ),+

WhereClause :
   where ( WherePredicate ),*

Targets: each Trait listed is implemented for the annotated type.

§On trait definitions

#[autoimpl] on trait definitions generates an implementation of that trait for the given targets over that targets’ own implementations of the trait. Targets may or may not be generic.

Method implementations either defer to a field (if using self._Member_ is specified; e.g. using self.0 or using self.inner) or use Deref (and, where required, DerefMut).

For example,

struct MyVec {
    vec: Vec<()>,
}

#[autoimpl(for MyVec using self.vec)]
trait IsEmpty {
    fn is_empty(&self) -> bool;
}

impl<T> IsEmpty for Vec<T> {
    fn is_empty(&self) -> bool {
        Vec::is_empty(self)
    }
}

Associated const and type items are only supported where the targets are generic over some parameter with a bound like T: trait. We call this the definitive type.

For example, the following usage implements MyTrait for targets &T, &mut T and Box<dyn MyTrait> using definitive type T:

#[autoimpl(for<T: trait + ?Sized> &T, &mut T, Box<T>)]
trait MyTrait {
    type X;

    fn f(&self) -> Self::X;
}

The expansion for target Box<T> looks like:

#[automatically_derived]
impl<T: MyTrait + ?Sized> MyTrait for Box<T> {
    type X = <T as MyTrait>::X;

    fn f(&self) -> Self::X {
        <T as MyTrait>::f(self)
    }
}

§Generics

Traits using generics and trait items using generics are, for the most part, supported.

Items with a where clause with a type bound on Self cannot be implemented via Deref since the item is not guaranteed to exist on the definitive type. Such items with a default implementation may be implemented using this that default implementation, though this results in a warning by default (requires feature “nightly-diagnostics”). In other cases an error is reported.

An example:

#[autoimpl(for<'a, T> &'a T, &'a mut T, Box<T> where T: trait + ?Sized)]
trait G<V>
where
    V: Debug,
{
    fn g(&self) -> V;

    fn s<X>(&self, f: impl Fn(V) -> X) -> X
    where
        Self: Sized,
    {
        f(self.g())
    }
}

§Parameter syntax

ParamsTrait :
   for Generics ( Type ),+ WhereClause?