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/// > ( _Trait_ ),+ _Using_? _Ignores_? _WhereClause_?
189/// >
190/// > _Using_ :\
191/// > `using` `self` `.` _Member_
192/// >
193/// > _Ignores_ :\
194/// > `ignore` ( `self` `.` _Member_ ),+
195/// >
196/// > _WhereClause_ :\
197/// > `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/// > `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/// > `impl_scope!` `{` _ScopeItem_ _ItemImpl_ * `}`
326/// >
327/// > _ScopeItem_ :\
328/// > _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}