Attribute Macro impl_tools::autoimpl

source · []
#[autoimpl]
Expand description

A variant of the standard derive macro

#[autoimpl] may be used in two ways:

  • On a type definition, to implement a specified trait (like #[derive])
  • On a trait definition, to re-implement that trait for a specified type supporting Deref

If using autoimpl and derive macros with Rust < 1.57.0, the autoimpl attribute must come first (see rust#81119).

Trait implementation

NamePathignoreusing
Clone::std::clone::Cloneinitialized with Default::default()-
Debug::std::fmt::Debugfield is not printed-
Default::std::default::Default--
Deref::std::ops::Deref-deref target
DerefMut::std::ops::DerefMut-deref target

Note: impl_default is a more flexible alternative to Default.

Ignore: trait supports ignoring fields (e.g. #[autoimpl(Debug ignore self.foo)]).

Using: trait requires a named field to “use”. Example: #[autoimpl(Deref using self.foo)] implements Deref to return (a reference to) field self.foo.

Traits are matched according to the path, via one of three forms:

  • Only the last component, e.g. #[autoimpl(Clone)]
  • The full path except leading ::, e.g. #[autoimpl(std::clone::Clone)]
  • The full path with leading ::, e.g. #[autoimpl(::std::clone::Clone)]

Note regarding no_std usage: the above table is wrong in that traits use paths in core or alloc, but also match std. That is, #[autoimpl(std::clone::Clone)] and #[autoimpl(core::clone::Clone)] are equivalent and generate an impl for ::core::clone::Clone.

Parameter syntax

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

Using :
   using self . Member

Ignores :
   ignore ( self . Member ),+

WhereClause :
   where ( WherePredicate ),*

Generics and where clause

Type generics are inherited from the type definition. Bounds defined by the type are inherited, but unlike #[derive] no additional bounds for the trait being implemented are assumed.

A where clause, e.g. where T: Foo, may be used. A special bound syntax, T: trait, indicates that T must support the trait being implemented.

Examples

Implement std::fmt::Debug, ignoring the last field:

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

Implement Clone and Debug on a wrapper, with the required bounds:

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

Implement Deref and DerefMut, dereferencing to the given field:

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

Trait re-implementation

User-defined traits may be implemented over any type supporting Deref (and if required DerefMut) to another type supporting the trait.

Parameter syntax

ParamsTrait :
   for Generics ( Type ),+ Definitive? WhereClause?

Generics :
   < ( GenericParam ) >

Definitive :
   using Type

Examples

Implement MyTrait for &T, &mut T and Box<dyn MyTrait>:

#[autoimpl(for<'a, T: trait + ?Sized> &'a T, &'a mut T, Box<T>)]
trait MyTrait {
    fn f(&self) -> String;
}

Note that the first parameter bound like T: trait is used as the definitive type (required). For example, here, f is implemented with the body <T as MyTrait>::f(self).

Note further: if the trait uses generic parameters itself, these must be introduced explicitly in the for<..> parameter list.