Attribute Macro impl_tools::autoimpl

source ·
#[autoimpl]
Expand description

An alternative to the standard derive macro

#[autoimpl] may be used in two ways:

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

On type definitions

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 from 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)]

Ignore: some trait implementations supports ignoring listed fields. For example, #[autoimpl(PartialEq ignore self.foo)] will implement PartialEq, comparing all fields except foo. Note: Copy and Eq do not use ignore, but tolerate its usage by a companion trait (e.g. #[autoimpl(PartialEq, Eq ignore self.a)]).

Using: some trait implementations require a named field to “use”. For example, #[autoimpl(Deref using self.foo)] implements Deref to return a reference to field self.foo.

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.

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.

Deref::Target type

The Deref trait has two members:

  • type Target: ?Sized
  • fn deref(&self) -> &Self::Target

#[autoimpl(Deref using self.x)] implements Deref as follows:

  • type Target = X where field x has type X
  • fn deref(&self) -> &Self::Target { &self.x }

For some uses this is fine, but in other cases a different Target type is preferred. To achieve this, Target may be given explicitly:

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

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);

On trait definitions

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 ),+ WhereClause?

Targets: the annotated trait is implemented for each Type listed.

Definitive type: It is required that some generic type parameter has bound trait (e.g. T: trait). The first such parameter is designated the definitive type.

Trait items

Assuming definitive type T, trait items are implemented as follows:

  • associated constant const C: const C = T::C;
  • associated type type X: type X = T::X;
  • method fn foo(a: A, b: B): T::foo(a, b)
  • (unexpanded) macro items: not supported

Generics and where clauses on types and methods are supported.

Items with a where clause with a type bound on Self are not supported since the item is not guaranteed to exist on the definitive type. Exception: methods with a default implementation (in this case the item is skipped).

Examples

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

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

The definitive type is T. 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.