From 86511548d589624a18f18b190e703d3cd6e2f53f Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 20 Dec 2024 12:33:41 +0000 Subject: [PATCH 1/5] Fix doc links --- lib/src/autoimpl.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/autoimpl.rs b/lib/src/autoimpl.rs index f9c1bbf..add9565 100644 --- a/lib/src/autoimpl.rs +++ b/lib/src/autoimpl.rs @@ -188,7 +188,7 @@ pub enum Error { } impl Error { - /// Report via [`proc_macro_error::emit_error`]. + /// Report via [`proc_macro_error2::emit_error`]. pub fn emit(self, target: Span, path_args: Span) { match self { Error::RequireUsing => { @@ -293,7 +293,7 @@ impl ImplTraits { /// This attribute does not modify the item. /// The caller should append the result to `item` tokens. /// - /// Errors are reported via [`proc_macro_error::emit_error`]. + /// Errors are reported via [`proc_macro_error2::emit_error`]. pub fn expand( self, item: Toks, From 5428e49f5a94ae1a0998c951a14af9354f17bdc1 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 20 Dec 2024 12:39:18 +0000 Subject: [PATCH 2/5] impl-tools doc: link macros --- src/lib.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2dfa442..7337ced 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,29 +9,31 @@ //! # Impl-tools //! -//! `#[autoimpl]` is a partial replacement for `#[derive]`, supporting: +//! [`#[autoimpl]`](macro@autoimpl) is a partial replacement for +//! [`#[derive]`](https://doc.rust-lang.org/stable/reference/attributes/derive.html), +//! supporting: //! //! - Explicit `where` clause on generic parameters //! - No implicit bounds on generic parameters beyond those required by the type //! - Traits like `Deref` by `using` a named field //! - Traits like `Debug` may `ignore` named fields //! -//! `#[autoimpl]` may also be used on trait definitions to *re-implement* the +//! [`#[autoimpl]`](macro@autoimpl) may also be used on trait definitions to *re-implement* the //! trait for given reference types. //! -//! `impl_scope!` is a function-like macro used to define a type plus its +//! [`impl_scope!`] is a function-like macro used to define a type plus its //! implementations. It supports two things: //! //! - `impl Self` syntax //! - Evaluation of advanced attribute macros, which may use field //! initializers and read/write other impls within the scope //! -//! `impl_anon!` is a function-like macro used to define and instantiate a -//! unique (single-use) type. It supports everything supported by `impl_scope!` +//! [`impl_anon!`] is a function-like macro used to define and instantiate a +//! unique (single-use) type. It supports everything supported by [`impl_scope!`] //! plus field initializers and (limited) automatic typing of fields. //! -//! User-extensions to both `#[autoimpl]` and `impl_scope!` are possible, by -//! writing your own proc-macro crate depending on +//! User-extensions to both [`#[autoimpl]`](macro@autoimpl) and [`impl_scope!`] +//! are possible, by writing your own proc-macro crate depending on //! [impl-tools-lib](https://crates.io/crates/impl-tools-lib). #[cfg(doctest)] From b7d383425c9b8363beeb6afc63450e40e8372b25 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 20 Dec 2024 13:20:04 +0000 Subject: [PATCH 3/5] Abbreviate lib top-level docs --- src/lib.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7337ced..d7ca041 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,31 +9,25 @@ //! # Impl-tools //! -//! [`#[autoimpl]`](macro@autoimpl) is a partial replacement for -//! [`#[derive]`](https://doc.rust-lang.org/stable/reference/attributes/derive.html), -//! supporting: +//! [`#[autoimpl]`](macro@autoimpl) is an alternative to +//! [`#[derive]`](macro@derive) with more features (also usable on traits). //! -//! - Explicit `where` clause on generic parameters -//! - No implicit bounds on generic parameters beyond those required by the type -//! - Traits like `Deref` by `using` a named field -//! - Traits like `Debug` may `ignore` named fields +//! [`#[impl_default]`](macro@impl_default) is shorthand for implementing +//! [`Default`] with an explicit default value. +//! It supports structs and enums. //! -//! [`#[autoimpl]`](macro@autoimpl) may also be used on trait definitions to *re-implement* the -//! trait for given reference types. +//! [`impl_scope!`] is a function-like macro used to define a type together with +//! its implementations. This allows: //! -//! [`impl_scope!`] is a function-like macro used to define a type plus its -//! implementations. It supports two things: -//! -//! - `impl Self` syntax -//! - Evaluation of advanced attribute macros, which may use field -//! initializers and read/write other impls within the scope +//! - `impl Self` syntax (avoid repeated definitions of generics) +//! - Evaluation of some more complex attribute macros //! //! [`impl_anon!`] is a function-like macro used to define and instantiate a //! unique (single-use) type. It supports everything supported by [`impl_scope!`] //! plus field initializers and (limited) automatic typing of fields. //! //! User-extensions to both [`#[autoimpl]`](macro@autoimpl) and [`impl_scope!`] -//! are possible, by writing your own proc-macro crate depending on +//! are possible with a custom proc-macro crate depending on //! [impl-tools-lib](https://crates.io/crates/impl-tools-lib). #[cfg(doctest)] From 89dcc3dfd3444b5ebb64ab16c8e220f4faa69ccf Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 20 Dec 2024 13:20:27 +0000 Subject: [PATCH 4/5] Revise doc for autoimpl (on type definitions) --- src/lib.rs | 123 ++++++++++++++++++++--------------------------------- 1 file changed, 46 insertions(+), 77 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d7ca041..8ca7c34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ use syn::parse_macro_input; use impl_tools_lib::{self as lib, autoimpl}; -/// Impl `Default` with given field or type initializers +/// Impl [`Default`] with given field or type initializers /// /// This macro may be used in one of two ways. /// @@ -106,20 +106,55 @@ pub fn impl_default(args: TokenStream, item: TokenStream) -> TokenStream { toks } -/// An alternative to the standard `derive` macro +/// An alternative to the standard [`macro@derive`] macro /// -/// `#[autoimpl]` may be used in two ways: +/// This macro may be used: /// -/// - [On a type definition](#on-type-definitions), to implement a specified trait (like `#[derive]`) +/// - [On a type definition](#on-type-definitions), to implement a specified trait /// - [On a trait definition](#on-trait-definitions), to implement the trait for specified types /// supporting [`Deref`] /// -/// If using `autoimpl` **and** `derive` macros with Rust < 1.57.0, the -/// `autoimpl` attribute must come first (see rust#81119). +/// # On type definitions /// -/// [`proc_macro_derive`]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros +/// `#[autoimpl]` on type definitions functions similarly to [`#[derive]`](macro@derive). The differences are as follows. /// -/// # On type definitions +/// 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: +/// ``` +/// # use impl_tools::autoimpl; +/// #[autoimpl(Clone, Debug where T: trait)] +/// struct Wrapper(pub T); +/// ``` +/// +/// ### `ignore` +/// +/// Traits like [`Debug`] may be implemented while `ignore`-ing some fields, for example: +/// ``` +/// # use impl_tools::autoimpl; +/// #[autoimpl(Debug ignore self.f)] +/// struct PairWithFn { +/// x: f32, +/// y: f32, +/// f: fn(&T), +/// } +/// ``` +/// +/// ### `using` +/// +/// Traits like [`Deref`] may be implemented by `using` a named field, for example: +/// ``` +/// # use impl_tools::autoimpl; +/// #[autoimpl(Deref, DerefMut using self.1)] +/// struct AnnotatedWrapper(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: +/// ``` +/// # use impl_tools::autoimpl; +/// #[autoimpl(Deref using self.0)] +/// struct MyBoxingWrapper(Box); +/// ``` +/// +/// ## Supported traits /// /// | Path | *ignore* | *using* | *notes* | /// |----- |--- |--- |--- | @@ -139,7 +174,7 @@ pub fn impl_default(args: TokenStream, item: TokenStream) -> TokenStream { /// | [`::core::ops::Deref`] | - | deref target | See [`Deref::Target` type](#dereftarget-type) below | /// | [`::core::ops::DerefMut`] | - | deref target | | /// -/// Traits are matched from the path, as follows: +/// 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)]` @@ -147,17 +182,7 @@ pub fn impl_default(args: TokenStream, item: TokenStream) -> TokenStream { /// - 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 +/// ## Parameter syntax /// /// > _ParamsMulti_ :\ /// >    ( _Trait_ ),+ _Using_? _Ignores_? _WhereClause_? @@ -173,63 +198,6 @@ pub fn impl_default(args: TokenStream, item: TokenStream) -> TokenStream { /// /// **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: -/// -/// ``` -/// # use impl_tools::autoimpl; -/// #[autoimpl(Deref using self.0)] -/// struct MyBoxingWrapper(Box); -/// ``` -/// -/// ### Examples -/// -/// Implement `std::fmt::Debug`, ignoring the last field: -/// ``` -/// # use impl_tools::autoimpl; -/// #[autoimpl(Debug ignore self.f)] -/// struct PairWithFn { -/// x: f32, -/// y: f32, -/// f: fn(&T), -/// } -/// ``` -/// -/// Implement `Clone` and `Debug` on a wrapper, with the required bounds: -/// ``` -/// # use impl_tools::autoimpl; -/// #[autoimpl(Clone, Debug where T: trait)] -/// struct Wrapper(pub T); -/// ``` -/// -/// Implement `Deref` and `DerefMut`, dereferencing to the given field: -/// ``` -/// # use impl_tools::autoimpl; -/// #[autoimpl(Deref, DerefMut using self.1)] -/// struct AnnotatedWrapper(String, T); -/// ``` /// /// # On trait definitions /// @@ -280,6 +248,7 @@ pub fn impl_default(args: TokenStream, item: TokenStream) -> TokenStream { /// introduced explicitly in the `for<..>` parameter list. /// /// [`Deref`]: std::ops::Deref +/// [`Deref::Target`]: std::ops::Deref::Target #[proc_macro_attribute] #[proc_macro_error] pub fn autoimpl(attr: TokenStream, item: TokenStream) -> TokenStream { From bf7a60f6a54e39ad4253b433ba0832907c1853bb Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 20 Dec 2024 14:38:28 +0000 Subject: [PATCH 5/5] 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 {