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/// NOTE: this macro is already partially obsolete since Rust 1.62 added support
50/// for [default enum variants](https://blog.rust-lang.org/2022/06/30/Rust-1.62.0/#default-enum-variants).
51/// Once [RFC 3681](https://github.com/rust-lang/rfcs/pull/3681) (default field values)
52/// is stable in this crate's MSRV, this macro will be deprecated.
53///
54/// ### Type-level initializer
55///
56/// ```
57/// # use impl_tools::impl_default;
58/// /// A simple enum; default value is Blue
59/// #[impl_default(Colour::Blue)]
60/// enum Colour {
61/// Red,
62/// Green,
63/// Blue,
64/// }
65///
66/// fn main() {
67/// assert!(matches!(Colour::default(), Colour::Blue));
68/// }
69/// ```
70///
71/// A where clause is optional: `#[impl_default(EXPR where BOUNDS)]`.
72///
73/// ### Field-level initializer
74///
75/// This variant only supports structs. Fields specified as `name: type = expr`
76/// will be initialized with `expr`, while other fields will be initialized with
77/// `Default::default()`.
78///
79/// ```
80/// # use impl_tools::{impl_default, impl_scope};
81/// impl_scope! {
82/// #[impl_default]
83/// struct Person {
84/// name: String = "Jane Doe".to_string(),
85/// age: u32 = 72,
86/// occupation: String,
87/// }
88/// }
89///
90/// fn main() {
91/// let person = Person::default();
92/// assert_eq!(person.name, "Jane Doe");
93/// assert_eq!(person.age, 72);
94/// assert_eq!(person.occupation, "");
95/// }
96/// ```
97///
98/// A where clause is optional: `#[impl_default(where BOUNDS)]`.
99#[proc_macro_attribute]
100#[proc_macro_error]
101pub fn impl_default(args: TokenStream, item: TokenStream) -> TokenStream {
102 let mut toks = item.clone();
103 match syn::parse::<lib::ImplDefault>(args) {
104 Ok(attr) => toks.extend(TokenStream::from(attr.expand(item.into()))),
105 Err(err) => {
106 emit_call_site_error!(err);
107 // Since this form of invocation only adds implementations, we can
108 // safely output the original item, thus reducing secondary errors.
109 }
110 }
111 toks
112}
113
114/// An alternative to the standard [`macro@derive`] macro
115///
116/// This macro may be used:
117///
118/// - [On a type definition](#on-type-definitions), to implement a specified trait
119/// - [On a trait definition](#on-trait-definitions), to implement the trait for specified types
120/// supporting [`Deref`]
121///
122/// # On type definitions
123///
124/// `#[autoimpl]` on type definitions functions similarly to [`#[derive]`](macro@derive). The differences are as follows.
125///
126/// 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:
127/// ```
128/// # use impl_tools::autoimpl;
129/// #[autoimpl(Clone, Debug where T: trait)]
130/// struct Wrapper<T>(pub T);
131/// ```
132///
133/// ### `ignore`
134///
135/// Traits like [`Debug`] may be implemented while `ignore`-ing some fields, for example:
136/// ```
137/// # use impl_tools::autoimpl;
138/// #[autoimpl(Debug ignore self.f)]
139/// struct PairWithFn<T> {
140/// x: f32,
141/// y: f32,
142/// f: fn(&T),
143/// }
144/// ```
145///
146/// ### `using`
147///
148/// Traits like [`Deref`] may be implemented by `using` a named field, for example:
149/// ```
150/// # use impl_tools::autoimpl;
151/// #[autoimpl(Deref, DerefMut using self.1)]
152/// struct AnnotatedWrapper<T>(String, T);
153/// ```
154/// In the above example, [`Deref::Target`] will be implemented as `T` (the type
155/// of the field `self.1`). The `Target` type may instead be specified explicitly:
156/// ```
157/// # use impl_tools::autoimpl;
158/// #[autoimpl(Deref<Target = T> using self.0)]
159/// struct MyBoxingWrapper<T: ?Sized>(Box<T>);
160/// ```
161///
162/// ## Supported traits
163///
164/// | Path | *ignore* | *using* | *notes* |
165/// |----- |--- |--- |--- |
166/// | [`::core::borrow::Borrow<T>`] | - | borrow target | `T` is type of target field |
167/// | [`::core::borrow::BorrowMut<T>`] | - | borrow target | `T` is type of target field |
168/// | [`::core::clone::Clone`] | yes | - | ignored fields use `Default::default()` |
169/// | [`::core::cmp::Eq`] | * | - | *allowed with `PartialEq` |
170/// | [`::core::cmp::Ord`] | yes | - | |
171/// | [`::core::cmp::PartialEq`] | yes | - | |
172/// | [`::core::cmp::PartialOrd`] | yes | - | |
173/// | [`::core::convert::AsRef<T>`] | - | ref target | `T` is type of target field |
174/// | [`::core::convert::AsMut<T>`] | - | ref target | `T` is type of target field |
175/// | [`::core::default::Default`] | - | - | [`macro@impl_default`] is a more flexible alternative |
176/// | [`::core::fmt::Debug`] | yes | - | |
177/// | [`::core::hash::Hash`] | yes | - | |
178/// | [`::core::marker::Copy`] | * | - | *allowed with `Clone` |
179/// | [`::core::ops::Deref`] | - | deref target | See [`Deref::Target` type](#dereftarget-type) below |
180/// | [`::core::ops::DerefMut`] | - | deref target | |
181///
182/// Traits are matched using the path, as follows:
183///
184/// - Only the last component, e.g. `#[autoimpl(Clone)]`
185/// - The full path with leading `::`, e.g. `#[autoimpl(::core::clone::Clone)]`
186/// - The full path without leading `::`, e.g. `#[autoimpl(core::clone::Clone)]`
187/// - The full path with/without leading `::`, using `std` instead of `core` or `alloc`,
188/// e.g. `#[autoimpl(std::clone::Clone)]`
189///
190/// ## Parameter syntax
191///
192/// > _ParamsMulti_ :\
193/// > ( _Trait_ ),+ _Using_? _Ignores_? _WhereClause_?
194/// >
195/// > _Using_ :\
196/// > `using` `self` `.` _Member_
197/// >
198/// > _Ignores_ :\
199/// > `ignore` ( `self` `.` _Member_ ),+
200/// >
201/// > _WhereClause_ :\
202/// > `where` ( _WherePredicate_ ),*
203///
204/// **Targets:** each *Trait* listed is implemented for the annotated type.
205///
206///
207/// # On trait definitions
208///
209/// `#[autoimpl]` on trait definitions generates an implementation of that trait
210/// for the given targets. This functions using an implementation of [`Deref`]
211/// (and, where required, [`DerefMut`]) to lower the target type to some other
212/// type supporting the trait. We call this latter type the **definitive type**.
213///
214/// It is required that the target type(s) implemented are generic over some
215/// type parameter(s). These generic parameters are introduced using `for<..>`.
216/// It is further required that at least one generic parameter has a bound on
217/// `trait`; the first such parameter is inferred to be the *definitive type*.
218///
219/// For example, the following usage implements `MyTrait` for targets `&T`,
220/// `&mut T` and `Box<dyn MyTrait>` using definitive type `T`:
221/// ```
222/// # use impl_tools::autoimpl;
223/// #[autoimpl(for<T: trait + ?Sized> &T, &mut T, Box<T>)]
224/// trait MyTrait {
225/// fn f(&self) -> String;
226/// }
227/// ```
228/// The expansion for target `Box<T>` looks like:
229/// ```
230/// # trait MyTrait {
231/// # fn f(&self) -> String;
232/// # }
233/// #[automatically_derived]
234/// impl<T: MyTrait + ?Sized> MyTrait for Box<T> {
235/// fn f(&self) -> String {
236/// <T as MyTrait>::f(self)
237/// }
238/// }
239/// ```
240///
241/// ## Generics
242///
243/// Traits using generics and trait items using generics are, for the most part,
244/// supported.
245///
246/// Items with a where clause with a type bound on `Self` are not supported
247/// since the item is not guaranteed to exist on the definitive type.
248/// Exception: methods with a default implementation (in this case the item is
249/// skipped).
250///
251/// An example:
252/// ```
253/// # use impl_tools::autoimpl;
254/// # use std::fmt::Debug;
255/// #[autoimpl(for<'a, T> &'a T, &'a mut T, Box<T> where T: trait + ?Sized)]
256/// trait G<V>
257/// where
258/// V: Debug,
259/// {
260/// fn g(&self) -> V;
261///
262/// fn s<X>(&self, f: impl Fn(V) -> X) -> X
263/// where
264/// Self: Sized,
265/// {
266/// f(self.g())
267/// }
268/// }
269/// ```
270///
271/// ## Parameter syntax
272///
273/// > _ParamsTrait_ :\
274/// > `for` _Generics_ ( _Type_ ),+ _WhereClause_?
275///
276/// [`Deref`]: std::ops::Deref
277/// [`Deref::Target`]: std::ops::Deref::Target
278/// [`DerefMut`]: std::ops::DerefMut
279#[proc_macro_attribute]
280#[proc_macro_error]
281pub fn autoimpl(attr: TokenStream, item: TokenStream) -> TokenStream {
282 let mut toks = item.clone();
283 match syn::parse::<autoimpl::Attr>(attr) {
284 Ok(autoimpl::Attr::ForDeref(ai)) => toks.extend(TokenStream::from(ai.expand(item.into()))),
285 Ok(autoimpl::Attr::ImplTraits(ai)) => {
286 // We could use lazy_static to construct a HashMap for fast lookups,
287 // but given the small number of impls a "linear map" is fine.
288 let find_impl = |path: &syn::Path| {
289 autoimpl::STD_IMPLS
290 .iter()
291 .cloned()
292 .find(|impl_| impl_.path().matches_ident_or_path(path))
293 };
294 toks.extend(TokenStream::from(ai.expand(item.into(), find_impl)))
295 }
296 Err(err) => {
297 emit_call_site_error!(err);
298 // Since autoimpl only adds implementations, we can safely output
299 // the original item, thus reducing secondary errors.
300 }
301 }
302 toks
303}
304
305/// Implement a type with `impl Self` syntax
306///
307/// This macro facilitates definition of a type (struct, enum or union) plus
308/// implementations via `impl Self { .. }` syntax: `Self` is expanded to the
309/// type's name, including generics and bounds (as defined on the type).
310///
311/// Caveat: `rustfmt` can not yet format contents (see
312/// [rustfmt#5254](https://github.com/rust-lang/rustfmt/issues/5254),
313/// [rustfmt#5538](https://github.com/rust-lang/rustfmt/pull/5538)).
314///
315/// Note: this macro is largely redundant with the [`macro@impl_self`] macro,
316/// the one exception being [`macro@impl_default`] support. This macro will be
317/// deprecated simultaneously with [`macro@impl_default`].
318///
319/// ## Special attribute macros
320///
321/// Additionally, `impl_scope!` supports special attribute macros evaluated
322/// within its scope:
323///
324/// - [`#[impl_default]`](macro@impl_default): implement [`Default`] using
325/// field initializers (which are not legal syntax outside of `impl_scope!`)
326///
327/// Note: matching these macros within `impl_scope!` does not use path
328/// resolution. Using `#[impl_tools::impl_default]` would resolve the variant
329/// of this macro which *doesn't support* field initializers.
330///
331/// ## Syntax
332///
333/// > _ImplScope_ :\
334/// > `impl_scope!` `{` _ScopeItem_ _ItemImpl_ * `}`
335/// >
336/// > _ScopeItem_ :\
337/// > _ItemEnum_ | _ItemStruct_ | _ItemType_ | _ItemUnion_
338///
339/// That is, one type definition followed by a set of implementations.
340/// Impls must take one of two forms:
341///
342/// - `impl Self { ... }` — generic parameters and bounds of the type are used
343/// - `impl MyType { ... }` where `MyType` matches the name of the defined type
344///
345/// Generic parameters from the type are included implicitly with the first form.
346/// Additional generic parameters and where clauses are supported (parameters
347/// and bounds are merged).
348///
349/// ## Example
350///
351/// ```
352/// impl_tools::impl_scope! {
353/// struct Pair<T>(T, T);
354///
355/// impl Self {
356/// pub fn new(a: T, b: T) -> Self {
357/// Pair(a, b)
358/// }
359/// }
360///
361/// impl Self where T: Clone {
362/// pub fn splat(a: T) -> Self {
363/// let b = a.clone();
364/// Pair(a, b)
365/// }
366/// }
367/// }
368/// ```
369#[proc_macro_error]
370#[proc_macro]
371pub fn impl_scope(input: TokenStream) -> TokenStream {
372 let mut scope = parse_macro_input!(input as scope::Scope);
373 scope.apply_attrs(scope::find_impl_default);
374 scope.expand().into()
375}
376
377/// Construct an anonymous struct
378///
379/// Rust doesn't currently support [`impl Trait { ... }` expressions](https://github.com/canndrew/rfcs/blob/impl-trait-expressions/text/0000-impl-trait-expressions.md)
380/// or implicit typing of struct fields. This macro is a **hack** allowing that.
381///
382/// Example:
383/// ```
384/// use std::fmt;
385/// fn main() {
386/// let world = "world";
387/// let says_hello_world = impl_tools::impl_anon! {
388/// struct(&'static str = world);
389/// impl fmt::Display for Self {
390/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391/// write!(f, "hello {}", self.0)
392/// }
393/// }
394/// };
395/// assert_eq!(format!("{}", says_hello_world), "hello world");
396/// }
397/// ```
398///
399/// That is, this macro creates an anonymous struct type (must be a struct),
400/// which may have trait implementations, then creates an instance of that
401/// struct.
402///
403/// Struct fields may have a fixed type or may be generic. Syntax is as follows:
404///
405/// - **regular struct:** `ident: ty = value`
406/// - **regular struct:** `ident: ty` (uses `Default` to construct value)
407/// - **regular struct:** `ident = value` (type is generic without bounds)
408/// - **tuple struct:** `ty = value`
409/// - **tuple struct:** `ty` (uses `Default` to construct value)
410///
411/// The field name, `ident`, may be `_` (anonymous field).
412///
413/// The field type, `ty`, may be or may contain inferred types (`_`) and/or
414/// `impl Trait` type expressions. These are substituted with generics on the
415/// type.
416///
417/// Refer to [examples](https://github.com/search?q=impl_anon+repo%3Akas-gui%2Fkas+path%3Aexamples&type=Code) for usage.
418#[proc_macro_error]
419#[proc_macro]
420pub fn impl_anon(input: TokenStream) -> TokenStream {
421 let mut scope = parse_macro_input!(input as anon::Anon).into_scope();
422 scope.apply_attrs(scope::find_impl_default);
423 scope.expand().into()
424}
425
426/// Implement a type with `impl Self` syntax
427///
428/// This attribute macro supports a type (struct, enum, type alias or union)
429/// definition plus associated `impl` items within a `mod`.
430///
431/// Macro expansion discards the `mod` entirely, placing all contents into the
432/// outer scope. This simplifies privacy rules in many use-cases, and highlights
433/// that the usage of `mod` is purely a hack to make the macro input valid Rust
434/// syntax (and thus compatible with `rustfmt`).
435///
436/// ## Syntax
437///
438/// > _ImplSelf_ :\
439/// > `#[impl_self]` `mod` _Name_ `{` _ScopeItem_ _ItemImpl_ * `}`
440/// >
441/// > _ScopeItem_ :\
442/// > _ItemEnum_ | _ItemStruct_ | _ItemType_ | _ItemUnion_
443///
444/// Here, _ItemEnum_, _ItemStruct_, _ItemType_ and _ItemUnion_ are `enum`,
445/// `struct`, `type` alias and `union` definitions respectively. Whichever of
446/// these is used, it must match the module name _Name_.
447///
448/// _ItemImpl_ is an `impl` item. It may use the standard implementation syntax
449/// (e.g. `impl Debug for MyType { .. }`) or `impl Self` syntax (see below).
450///
451/// The `mod` may not contain any other items, except `doc` items (documentation
452/// on the module itself is ignored in favour of documentation on the defined
453/// type) and attributes (which apply as usual).
454///
455/// ### `impl Self` syntax
456///
457/// `impl Self` "syntax" is syntactically-valid (but not semantically-valid)
458/// Rust syntax for writing inherent and trait `impl` blocks:
459///
460/// - `impl Self { ... }` — an inherent `impl` item on the defined type
461/// - `impl Debug for Self { ... }` — a trait `impl` item on the defined type
462///
463/// Generic parameters and bounds are copied from the type definition.
464/// Additional generic parameters may be specified; these extend the list of
465/// generic parameters on the type itself, and thus must have distinct names.
466/// Additional bounds (where clauses) may be specified; these extend the list of
467/// bounds on the type itself.
468///
469/// ## Example
470///
471/// ```
472/// #[impl_tools::impl_self]
473/// mod Pair {
474/// /// A pair of values of type `T`
475/// pub struct Pair<T>(T, T);
476///
477/// impl Self {
478/// pub fn new(a: T, b: T) -> Self {
479/// Pair(a, b)
480/// }
481/// }
482///
483/// impl Self where T: Clone {
484/// pub fn splat(a: T) -> Self {
485/// let b = a.clone();
486/// Pair(a, b)
487/// }
488/// }
489/// }
490/// ```
491#[proc_macro_attribute]
492#[proc_macro_error]
493pub fn impl_self(attr: TokenStream, input: TokenStream) -> TokenStream {
494 let _ = parse_macro_input!(attr as scope::ScopeModAttrs);
495 let scope = parse_macro_input!(input as scope::ScopeMod);
496 scope.contents.expand().into()
497}