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