auto_impl/lib.rs
1//! A proc-macro attribute for automatically implementing a trait for
2//! references, some common smart pointers and closures.
3//!
4//! ## Simple example
5//!
6//! ```
7//! use auto_impl::auto_impl;
8//!
9//! // This will generate two additional impl blocks: one `for &T` and one
10//! // `for Box<T>` where `T: Foo`.
11//! #[auto_impl(&, Box)]
12//! trait Foo {
13//! fn foo(&self);
14//! }
15//!
16//! impl Foo for i32 {
17//! fn foo(&self) {}
18//! }
19//!
20//! fn requires_foo(_: impl Foo) {}
21//!
22//!
23//! requires_foo(0i32); // works: through the impl we defined above
24//! requires_foo(&0i32); // works: through the generated impl
25//! requires_foo(Box::new(0i32)); // works: through the generated impl
26//! ```
27//!
28//!
29//! # Basic syntax and supported types
30//!
31//! You can annotate your trait with the `#[auto_impl(...)]` attribute. That
32//! attribute can only be used on traits and not on structs, enums or anything
33//! else.
34//!
35//! In the attribute, you have to specify all so called *proxy types* (the
36//! types you want to generate impls for) as a comma separated list. Each proxy
37//! type has a short abbreviation that you have to list there.
38//!
39//! Currently the following proxy types are supported:
40//!
41//! | Abbreviation | Example generated impl |
42//! | ------------ | ---------------------- |
43//! | `&` | `impl<T: Trait> Trait for &T` |
44//! | `&mut` | `impl<T: Trait> Trait for &mut T` |
45//! | `Box` | `impl<T: Trait> Trait for Box<T>` |
46//! | `Rc` | `impl<T: Trait> Trait for Rc<T>` |
47//! | `Arc` | `impl<T: Trait> Trait for Arc<T>` |
48//! | `Fn` | `impl<T: Fn()> Trait for T` |
49//! | `FnMut` | `impl<T: FnMut()> Trait for T` |
50//! | `FnOnce` | `impl<T: FnOnce()> Trait for T` |
51//!
52//!
53//! # More examples
54//!
55//! More examples can be found in [the examples folder][examples]. In
56//! particular, the `greet_closure` example shows how to use the `Fn*` proxy
57//! types.
58//!
59//! [examples]: https://github.com/auto-impl-rs/auto_impl/tree/master/examples
60//!
61//! The following example shows that a trait can contain associated consts,
62//! associated types and complex methods (with generics, bounds, ...).
63//!
64//! ```
65//! use auto_impl::auto_impl;
66//! use std::{fmt, rc::Rc};
67//!
68//!
69//! #[auto_impl(&, &mut, Box, Rc)]
70//! trait Animal {
71//! const NUMBER_OF_LEGS: u8;
72//!
73//! type Name: fmt::Display;
74//! fn name(&self) -> Self::Name;
75//!
76//! fn select_favorite<'a, I>(&self, toys: I) -> &'a str
77//! where
78//! I: Iterator<Item = &'a str>;
79//! }
80//!
81//! struct Dog(String);
82//!
83//! impl Animal for Dog {
84//! const NUMBER_OF_LEGS: u8 = 4;
85//!
86//! type Name = String;
87//! fn name(&self) -> Self::Name {
88//! self.0.clone()
89//! }
90//!
91//! fn select_favorite<'a, I>(&self, mut toys: I) -> &'a str
92//! where
93//! I: Iterator<Item = &'a str>
94//! {
95//! toys.next().unwrap()
96//! }
97//! }
98//!
99//! fn require_animal(_: impl Animal) {}
100//!
101//! // All these calls work, as the `#[auto_impl]` attribute generated four
102//! // impls for all those proxy types
103//! require_animal(Dog("Doggo".into()));
104//! require_animal(&Dog("Doggo".into()));
105//! require_animal(&mut Dog("Doggo".into()));
106//! require_animal(Box::new(Dog("Doggo".into())));
107//! require_animal(Rc::new(Dog("Doggo".into())));
108//! ```
109//!
110//!
111//! # Restriction of references and smart pointers
112//!
113//! Not every trait can be implemented for every proxy type. As an easy
114//! example, consider this trait:
115//!
116//! ```
117//! trait Bar {
118//! fn bar(&mut self);
119//! }
120//! ```
121//!
122//! If we try to implement it for immutable references via `#[auto_impl(&)]`
123//! the following impl would be generated:
124//!
125//! ```ignore
126//! impl<T: Bar> Bar for &T {
127//! fn bar(&mut self) {
128//! T::bar(*self) // fails to compile
129//! }
130//! }
131//! ```
132//!
133//! As you can easily see, this won't work because we can't call `bar` through
134//! an immutable reference. There are similar restrictions for many other
135//! smart pointers and references.
136//!
137//! In the following table you can see which methods can be implemented for
138//! which proxy type. If a trait contains at least one method that cannot be
139//! implemented for a proxy type, you cannot implement the trait for that proxy
140//! type.
141//!
142//! | Trait contains method with... | `&` | `&mut` | `Box` | `Rc` | `Arc` |
143//! | ----------------------------- | --- | ------ | ----- | ---- | ----- |
144//! | `&self` receiver | ✔ | ✔ | ✔ | ✔ | ✔ |
145//! | `&mut self` receiver | ✗ | ✔ | ✔ | ✗ | ✗ |
146//! | `self` receiver | ✗ | ✗ | ✔ | ✗ | ✗ |
147//! | no `self` receiver | ✔ | ✔ | ✔ | ✔ | ✔ |
148//!
149//! References and smart pointers have **no restriction in regard to associated
150//! types and associated consts**! Meaning: traits with associated types/consts
151//! can always be implemented for references and smart pointers as long as the
152//! methods of that trait can be implemented.
153//!
154//!
155//! # Restriction of closure types (`Fn*` traits)
156//!
157//! The `Fn*` proxy types have a lot more restrictions than references and
158//! smart pointer:
159//! - the trait must not define any associated types or consts
160//! - the trait must define **exactly one** method
161//! - the method must have a `self` receiver
162//! - the method must not return anything borrowed from `self`
163//! - the method must not have generic type or const parameters
164//!
165//! Additionally, some `Fn*` traits cannot be implemented for all `self`
166//! receiver types:
167//!
168//! | `self` Receiver | `Fn` | `FnMut` | `FnOnce` |
169//! | --------------- | ---- | ------- | -------- |
170//! | `&self` | ✔ | ✗ | ✗ |
171//! | `&mut self` | ✔ | ✔ | ✗ |
172//! | `self` | ✔ | ✔ | ✔ |
173//!
174//! Lastly, the impls generated for the `Fn*` proxy types contain `for T`. This
175//! is the most general blanket impl. So just be aware of the problems with
176//! coherence and orphan rules that can emerge due to this impl.
177//!
178//!
179//! # The `keep_default_for` attribute for methods
180//!
181//! By default, the impls generated by `auto_impl` will overwrite all methods
182//! of the trait, even those with default implementation. Sometimes, you want
183//! to not overwrite default methods and instead use the default
184//! implementation. You can do that by adding the
185//! `#[auto_impl(keep_default_for(...))]` attribute to a default method. In the
186//! parenthesis you need to list all proxy types for which the default method
187//! should be kept.
188//!
189//! From [the `keep_default_for` example](
190//! https://github.com/auto-impl-rs/auto_impl/blob/master/examples/keep_default_for.rs):
191//!
192//! ```
193//! # use auto_impl::auto_impl;
194//! #[auto_impl(&, Box)]
195//! trait Foo {
196//! fn required(&self) -> String;
197//!
198//! // The generated impl for `&T` will not override this method.
199//! #[auto_impl(keep_default_for(&))]
200//! fn provided(&self) {
201//! println!("Hello {}", self.required());
202//! }
203//! }
204//! ```
205
206extern crate proc_macro;
207#[macro_use]
208extern crate quote;
209
210use proc_macro::TokenStream;
211use proc_macro2::TokenStream as TokenStream2;
212use proc_macro_error::{abort_call_site, proc_macro_error, set_dummy};
213use quote::ToTokens;
214
215mod analyze;
216mod attr;
217mod gen;
218mod proxy;
219
220/// See crate documentation for more information.
221#[proc_macro_error]
222#[proc_macro_attribute]
223pub fn auto_impl(args: TokenStream, input: TokenStream) -> TokenStream {
224 // Make sure that we emit a dummy in case of error
225 let input: TokenStream2 = input.into();
226 set_dummy(input.clone());
227
228 // Try to parse the token stream from the attribute to get a list of proxy
229 // types.
230 let proxy_types = proxy::parse_types(args);
231
232 match syn::parse2::<syn::ItemTrait>(input) {
233 // The attribute was applied to a valid trait. Now it's time to execute
234 // the main step: generate a token stream which contains an impl of the
235 // trait for each proxy type.
236 Ok(mut trait_def) => {
237 let generated = gen::gen_impls(&proxy_types, &trait_def);
238
239 // Before returning the trait definition, we have to remove all
240 // `#[auto_impl(...)]` attributes on all methods.
241 attr::remove_our_attrs(&mut trait_def);
242
243 // We emit modified input instead of the original one
244 // since it's better to remove our attributes even in case of error
245 set_dummy(trait_def.to_token_stream());
246
247 quote!(#trait_def #generated).into()
248 }
249
250 // If the token stream could not be parsed as trait, this most
251 // likely means that the attribute was applied to a non-trait item.
252 // Even if the trait definition was syntactically incorrect, the
253 // compiler usually does some kind of error recovery to proceed. We
254 // get the recovered tokens.
255 Err(e) => abort_call_site!(
256 "couldn't parse trait item";
257 note = e;
258 note = "the #[auto_impl] attribute can only be applied to traits!";
259 ),
260 }
261}