impl_tools/
lib.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6#![allow(clippy::needless_doctest_main)]
7// Lint advocates use of bool::then_some, stablizied in rustc 1.62.0
8#![allow(clippy::unnecessary_lazy_evaluations)]
9
10//! # Impl-tools
11//!
12//! [`#[autoimpl]`](macro@autoimpl) is an alternative to
13//! [`#[derive]`](macro@derive) with more features (also usable on traits).
14//!
15//! [`#[impl_default]`](macro@impl_default) is shorthand for implementing
16//! [`Default`] with an explicit default value.
17//! It supports structs and enums.
18//!
19//! [`impl_scope!`] is a function-like macro used to define a type together with
20//! its implementations. This allows:
21//!
22//! -   `impl Self` syntax (avoid repeated definitions of generics)
23//! -   Evaluation of some more complex attribute macros
24//!
25//! [`impl_anon!`] is a function-like macro used to define and instantiate a
26//! unique (single-use) type. It supports everything supported by [`impl_scope!`]
27//! plus field initializers and (limited) automatic typing of fields.
28//!
29//! User-extensions to both [`#[autoimpl]`](macro@autoimpl) and [`impl_scope!`]
30//! are possible with a custom proc-macro crate depending on
31//! [impl-tools-lib](https://crates.io/crates/impl-tools-lib).
32
33#[cfg(doctest)]
34doc_comment::doctest!("../README.md");
35
36extern crate proc_macro;
37
38use lib::{anon, scope};
39use proc_macro::TokenStream;
40use proc_macro_error2::{emit_call_site_error, proc_macro_error};
41use syn::parse_macro_input;
42
43use impl_tools_lib::{self as lib, autoimpl};
44
45/// Impl [`Default`] with given field or type initializers
46///
47/// This macro may be used in one of two ways.
48///
49/// ### Type-level initializer
50///
51/// ```
52/// # use impl_tools::impl_default;
53/// /// A simple enum; default value is Blue
54/// #[impl_default(Colour::Blue)]
55/// enum Colour {
56///     Red,
57///     Green,
58///     Blue,
59/// }
60///
61/// fn main() {
62///     assert!(matches!(Colour::default(), Colour::Blue));
63/// }
64/// ```
65///
66/// A where clause is optional: `#[impl_default(EXPR where BOUNDS)]`.
67///
68/// ### Field-level initializer
69///
70/// This variant only supports structs. Fields specified as `name: type = expr`
71/// will be initialized with `expr`, while other fields will be initialized with
72/// `Default::default()`.
73///
74/// ```
75/// # use impl_tools::{impl_default, impl_scope};
76/// impl_scope! {
77///     #[impl_default]
78///     struct Person {
79///         name: String = "Jane Doe".to_string(),
80///         age: u32 = 72,
81///         occupation: String,
82///     }
83/// }
84///
85/// fn main() {
86///     let person = Person::default();
87///     assert_eq!(person.name, "Jane Doe");
88///     assert_eq!(person.age, 72);
89///     assert_eq!(person.occupation, "");
90/// }
91/// ```
92///
93/// A where clause is optional: `#[impl_default(where BOUNDS)]`.
94#[proc_macro_attribute]
95#[proc_macro_error]
96pub fn impl_default(args: TokenStream, item: TokenStream) -> TokenStream {
97    let mut toks = item.clone();
98    match syn::parse::<lib::ImplDefault>(args) {
99        Ok(attr) => toks.extend(TokenStream::from(attr.expand(item.into()))),
100        Err(err) => {
101            emit_call_site_error!(err);
102            // Since this form of invocation only adds implementations, we can
103            // safely output the original item, thus reducing secondary errors.
104        }
105    }
106    toks
107}
108
109/// An alternative to the standard [`macro@derive`] macro
110///
111/// This macro may be used:
112///
113/// -   [On a type definition](#on-type-definitions), to implement a specified trait
114/// -   [On a trait definition](#on-trait-definitions), to implement the trait for specified types
115///     supporting [`Deref`]
116///
117/// # On type definitions
118///
119/// `#[autoimpl]` on type definitions functions similarly to [`#[derive]`](macro@derive). The differences are as follows.
120///
121/// 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:
122/// ```
123/// # use impl_tools::autoimpl;
124/// #[autoimpl(Clone, Debug where T: trait)]
125/// struct Wrapper<T>(pub T);
126/// ```
127///
128/// ### `ignore`
129///
130/// Traits like [`Debug`] may be implemented while `ignore`-ing some fields, for example:
131/// ```
132/// # use impl_tools::autoimpl;
133/// #[autoimpl(Debug ignore self.f)]
134/// struct PairWithFn<T> {
135///     x: f32,
136///     y: f32,
137///     f: fn(&T),
138/// }
139/// ```
140///
141/// ### `using`
142///
143/// Traits like [`Deref`] may be implemented by `using` a named field, for example:
144/// ```
145/// # use impl_tools::autoimpl;
146/// #[autoimpl(Deref, DerefMut using self.1)]
147/// struct AnnotatedWrapper<T>(String, T);
148/// ```
149/// In the above example, [`Deref::Target`] will be implemented as `T` (the type
150/// of the field `self.1`). The `Target` type may instead be specified explicitly:
151/// ```
152/// # use impl_tools::autoimpl;
153/// #[autoimpl(Deref<Target = T> using self.0)]
154/// struct MyBoxingWrapper<T: ?Sized>(Box<T>);
155/// ```
156///
157/// ## Supported traits
158///
159/// | Path | *ignore* | *using* | *notes* |
160/// |----- |--- |--- |--- |
161/// | [`::core::borrow::Borrow<T>`] | - | borrow target | `T` is type of target field |
162/// | [`::core::borrow::BorrowMut<T>`] | - | borrow target | `T` is type of target field |
163/// | [`::core::clone::Clone`] | yes | - | ignored fields use `Default::default()` |
164/// | [`::core::cmp::Eq`] | * | - | *allowed with `PartialEq` |
165/// | [`::core::cmp::Ord`] | yes | - | |
166/// | [`::core::cmp::PartialEq`] | yes | - | |
167/// | [`::core::cmp::PartialOrd`] | yes | - | |
168/// | [`::core::convert::AsRef<T>`] | - | ref target | `T` is type of target field |
169/// | [`::core::convert::AsMut<T>`] | - | ref target | `T` is type of target field |
170/// | [`::core::default::Default`] | - | - | [`macro@impl_default`] is a more flexible alternative |
171/// | [`::core::fmt::Debug`] | yes | - | |
172/// | [`::core::hash::Hash`] | yes | - | |
173/// | [`::core::marker::Copy`] | * | - | *allowed with `Clone` |
174/// | [`::core::ops::Deref`] | - | deref target | See [`Deref::Target` type](#dereftarget-type) below |
175/// | [`::core::ops::DerefMut`] | - | deref target | |
176///
177/// Traits are matched using the path, as follows:
178///
179/// -   Only the last component, e.g. `#[autoimpl(Clone)]`
180/// -   The full path with leading `::`, e.g. `#[autoimpl(::core::clone::Clone)]`
181/// -   The full path without leading `::`, e.g. `#[autoimpl(core::clone::Clone)]`
182/// -   The full path with/without leading `::`, using `std` instead of `core` or `alloc`,
183///     e.g. `#[autoimpl(std::clone::Clone)]`
184///
185/// ## Parameter syntax
186///
187/// > _ParamsMulti_ :\
188/// > &nbsp;&nbsp; ( _Trait_ ),+ _Using_? _Ignores_? _WhereClause_?
189/// >
190/// > _Using_ :\
191/// > &nbsp;&nbsp; `using` `self` `.` _Member_
192/// >
193/// > _Ignores_ :\
194/// > &nbsp;&nbsp; `ignore` ( `self` `.` _Member_ ),+
195/// >
196/// > _WhereClause_ :\
197/// > &nbsp;&nbsp; `where` ( _WherePredicate_ ),*
198///
199/// **Targets:** each *Trait* listed is implemented for the annotated type.
200///
201///
202/// # On trait definitions
203///
204/// `#[autoimpl]` on trait definitions generates an implementation of that trait
205/// for the given targets. This functions using an implementation of [`Deref`]
206/// (and, where required, [`DerefMut`]) to lower the target type to some other
207/// type supporting the trait. We call this latter type the **definitive type**.
208///
209/// It is required that the target type(s) implemented are generic over some
210/// type parameter(s). These generic parameters are introduced using `for<..>`.
211/// It is further required that at least one generic parameter has a bound on
212/// `trait`; the first such parameter is inferred to be the *definitive type*.
213///
214/// For example, the following usage implements `MyTrait` for targets `&T`,
215/// `&mut T` and `Box<dyn MyTrait>` using definitive type `T`:
216/// ```
217/// # use impl_tools::autoimpl;
218/// #[autoimpl(for<T: trait + ?Sized> &T, &mut T, Box<T>)]
219/// trait MyTrait {
220///     fn f(&self) -> String;
221/// }
222/// ```
223/// The expansion for target `Box<T>` looks like:
224/// ```
225/// # trait MyTrait {
226/// #     fn f(&self) -> String;
227/// # }
228/// #[automatically_derived]
229/// impl<T: MyTrait + ?Sized> MyTrait for Box<T> {
230///     fn f(&self) -> String {
231///         <T as MyTrait>::f(self)
232///     }
233/// }
234/// ```
235///
236/// ## Generics
237///
238/// Traits using generics and trait items using generics are, for the most part,
239/// supported.
240///
241/// Items with a where clause with a type bound on `Self` are not supported
242/// since the item is not guaranteed to exist on the definitive type.
243/// Exception: methods with a default implementation (in this case the item is
244/// skipped).
245///
246/// An example:
247/// ```
248/// # use impl_tools::autoimpl;
249/// # use std::fmt::Debug;
250/// #[autoimpl(for<'a, T> &'a T, &'a mut T, Box<T> where T: trait + ?Sized)]
251/// trait G<V>
252/// where
253///     V: Debug,
254/// {
255///     fn g(&self) -> V;
256///
257///     fn s<X>(&self, f: impl Fn(V) -> X) -> X
258///     where
259///         Self: Sized,
260///     {
261///         f(self.g())
262///     }
263/// }
264/// ```
265///
266/// ## Parameter syntax
267///
268/// > _ParamsTrait_ :\
269/// > &nbsp;&nbsp; `for` _Generics_ ( _Type_ ),+ _WhereClause_?
270///
271/// [`Deref`]: std::ops::Deref
272/// [`Deref::Target`]: std::ops::Deref::Target
273/// [`DerefMut`]: std::ops::DerefMut
274#[proc_macro_attribute]
275#[proc_macro_error]
276pub fn autoimpl(attr: TokenStream, item: TokenStream) -> TokenStream {
277    let mut toks = item.clone();
278    match syn::parse::<autoimpl::Attr>(attr) {
279        Ok(autoimpl::Attr::ForDeref(ai)) => toks.extend(TokenStream::from(ai.expand(item.into()))),
280        Ok(autoimpl::Attr::ImplTraits(ai)) => {
281            // We could use lazy_static to construct a HashMap for fast lookups,
282            // but given the small number of impls a "linear map" is fine.
283            let find_impl = |path: &syn::Path| {
284                autoimpl::STD_IMPLS
285                    .iter()
286                    .cloned()
287                    .find(|impl_| impl_.path().matches_ident_or_path(path))
288            };
289            toks.extend(TokenStream::from(ai.expand(item.into(), find_impl)))
290        }
291        Err(err) => {
292            emit_call_site_error!(err);
293            // Since autoimpl only adds implementations, we can safely output
294            // the original item, thus reducing secondary errors.
295        }
296    }
297    toks
298}
299
300/// Implement a type with `impl Self` syntax
301///
302/// This macro facilitates definition of a type (struct, enum or union) plus
303/// implementations via `impl Self { .. }` syntax: `Self` is expanded to the
304/// type's name, including generics and bounds (as defined on the type).
305///
306/// Caveat: `rustfmt` can not yet format contents (see
307/// [rustfmt#5254](https://github.com/rust-lang/rustfmt/issues/5254),
308/// [rustfmt#5538](https://github.com/rust-lang/rustfmt/pull/5538)).
309///
310/// ## Special attribute macros
311///
312/// Additionally, `impl_scope!` supports special attribute macros evaluated
313/// within its scope:
314///
315/// -   [`#[impl_default]`](macro@impl_default): implement [`Default`] using
316///     field initializers (which are not legal syntax outside of `impl_scope!`)
317///
318/// Note: matching these macros within `impl_scope!` does not use path
319/// resolution. Using `#[impl_tools::impl_default]` would resolve the variant
320/// of this macro which *doesn't support* field initializers.
321///
322/// ## Syntax
323///
324/// > _ImplScope_ :\
325/// > &nbsp;&nbsp; `impl_scope!` `{` _ScopeItem_ _ItemImpl_ * `}`
326/// >
327/// > _ScopeItem_ :\
328/// > &nbsp;&nbsp; _ItemEnum_ | _ItemStruct_ | _ItemType_ | _ItemUnion_
329///
330/// That is, one type definition followed by a set of implementations.
331/// Impls must take one of two forms:
332///
333/// -   `impl Self { ... }` — generic parameters and bounds of the type are used
334/// -   `impl MyType { ... }` where `MyType` matches the name of the defined type
335///
336/// Generic parameters from the type are included implicitly with the first form.
337/// Additional generic parameters and where clauses are supported (parameters
338/// and bounds are merged).
339///
340/// ## Example
341///
342/// ```
343/// impl_tools::impl_scope! {
344///     struct Pair<T>(T, T);
345///
346///     impl Self {
347///         pub fn new(a: T, b: T) -> Self {
348///             Pair(a, b)
349///         }
350///     }
351///
352///     impl Self where T: Clone {
353///         pub fn splat(a: T) -> Self {
354///             let b = a.clone();
355///             Pair(a, b)
356///         }
357///     }
358/// }
359/// ```
360#[proc_macro_error]
361#[proc_macro]
362pub fn impl_scope(input: TokenStream) -> TokenStream {
363    let mut scope = parse_macro_input!(input as scope::Scope);
364    scope.apply_attrs(scope::find_impl_default);
365    scope.expand().into()
366}
367
368/// Construct an anonymous struct
369///
370/// Rust doesn't currently support [`impl Trait { ... }` expressions](https://github.com/canndrew/rfcs/blob/impl-trait-expressions/text/0000-impl-trait-expressions.md)
371/// or implicit typing of struct fields. This macro is a **hack** allowing that.
372///
373/// Example:
374/// ```
375/// use std::fmt;
376/// fn main() {
377///     let world = "world";
378///     let says_hello_world = impl_tools::impl_anon! {
379///         struct(&'static str = world);
380///         impl fmt::Display for Self {
381///             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382///                 write!(f, "hello {}", self.0)
383///             }
384///         }
385///     };
386///     assert_eq!(format!("{}", says_hello_world), "hello world");
387/// }
388/// ```
389///
390/// That is, this macro creates an anonymous struct type (must be a struct),
391/// which may have trait implementations, then creates an instance of that
392/// struct.
393///
394/// Struct fields may have a fixed type or may be generic. Syntax is as follows:
395///
396/// -   **regular struct:** `ident: ty = value`
397/// -   **regular struct:** `ident: ty` (uses `Default` to construct value)
398/// -   **regular struct:** `ident = value` (type is generic without bounds)
399/// -   **tuple struct:** `ty = value`
400/// -   **tuple struct:** `ty` (uses `Default` to construct value)
401///
402/// The field name, `ident`, may be `_` (anonymous field).
403///
404/// The field type, `ty`, may be or may contain inferred types (`_`) and/or
405/// `impl Trait` type expressions. These are substituted with generics on the
406/// type.
407///
408/// Refer to [examples](https://github.com/search?q=impl_anon+repo%3Akas-gui%2Fkas+path%3Aexamples&type=Code) for usage.
409#[proc_macro_error]
410#[proc_macro]
411pub fn impl_anon(input: TokenStream) -> TokenStream {
412    let mut scope = parse_macro_input!(input as anon::Anon).into_scope();
413    scope.apply_attrs(scope::find_impl_default);
414    scope.expand().into()
415}