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;
211
212mod analyze;
213mod attr;
214mod gen;
215mod proxy;
216
217/// See crate documentation for more information.
218#[proc_macro_attribute]
219pub fn auto_impl(args: TokenStream, input: TokenStream) -> TokenStream {
220 match auto_impl2(args, input.into()) {
221 Ok(tokens) => tokens.into(),
222 Err(e) => e.into_compile_error().into(),
223 }
224}
225
226fn auto_impl2(
227 args: TokenStream,
228 input: proc_macro2::TokenStream,
229) -> syn::Result<proc_macro2::TokenStream> {
230 // Try to parse the token stream from the attribute to get a list of proxy
231 // types.
232 let proxy_types = proxy::parse_types(args);
233
234 let mut trait_def = syn::parse2::<syn::ItemTrait>(input)?;
235
236 let generated = gen::gen_impls(&proxy_types, &trait_def)?;
237
238 // Before returning the trait definition, we have to remove all
239 // `#[auto_impl(...)]` attributes on all methods.
240 attr::remove_our_attrs(&mut trait_def)?;
241
242 Ok(quote!(#trait_def #generated))
243}