From bf7a60f6a54e39ad4253b433ba0832907c1853bb Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 20 Dec 2024 14:38:28 +0000 Subject: [PATCH] Revise doc for #[autoimpl] (on trait definitions) --- src/lib.rs | 86 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8ca7c34..2606c96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,54 +201,76 @@ pub fn impl_default(args: TokenStream, item: TokenStream) -> TokenStream { /// /// # 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: +/// `#[autoimpl]` on trait definitions generates an implementation of that trait +/// for the given targets. This functions using an implementation of [`Deref`] +/// (and, where required, [`DerefMut`]) to lower the target type to some other +/// type supporting the trait. We call this latter type the **definitive type**. +/// +/// It is required that the target type(s) implemented are generic over some +/// type parameter(s). These generic parameters are introduced using `for<..>`. +/// It is further required that at least one generic parameter has a bound on +/// `trait`; the first such parameter is inferred to be the *definitive type*. +/// +/// For example, the following usage implements `MyTrait` for targets `&T`, +/// `&mut T` and `Box` using definitive type `T`: +/// ``` +/// # use impl_tools::autoimpl; +/// #[autoimpl(for &T, &mut T, Box)] +/// trait MyTrait { +/// fn f(&self) -> String; +/// } +/// ``` +/// The expansion for target `Box` looks like: +/// ``` +/// # trait MyTrait { +/// # fn f(&self) -> String; +/// # } +/// #[automatically_derived] +/// impl MyTrait for Box { +/// fn f(&self) -> String { +/// ::f(self) +/// } +/// } +/// ``` /// -/// - 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 /// -/// Generics and where clauses on types and methods are supported. +/// 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` 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`: +/// An example: /// ``` /// # use impl_tools::autoimpl; -/// #[autoimpl(for &T, &mut T, Box)] -/// trait MyTrait { -/// fn f(&self) -> String; +/// # use std::fmt::Debug; +/// #[autoimpl(for<'a, T> &'a T, &'a mut T, Box where T: trait + ?Sized)] +/// trait G +/// where +/// V: Debug, +/// { +/// fn g(&self) -> V; +/// +/// fn s(&self, f: impl Fn(V) -> X) -> X +/// where +/// Self: Sized, +/// { +/// f(self.g()) +/// } /// } /// ``` -/// The definitive type is `T`. For example, here, `f` is implemented with the -/// body `::f(self)`. /// -/// Note further: if the trait uses generic parameters itself, these must be -/// introduced explicitly in the `for<..>` parameter list. +/// ## Parameter syntax +/// +/// > _ParamsTrait_ :\ +/// >    `for` _Generics_ ( _Type_ ),+ _WhereClause_? /// /// [`Deref`]: std::ops::Deref /// [`Deref::Target`]: std::ops::Deref::Target +/// [`DerefMut`]: std::ops::DerefMut #[proc_macro_attribute] #[proc_macro_error] pub fn autoimpl(attr: TokenStream, item: TokenStream) -> TokenStream {