├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── examples ├── README.md ├── async_await │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── error_messages.rs ├── greet_closure.rs ├── keep_default_for.rs ├── names.rs └── refs.rs ├── rustfmt.toml ├── src ├── analyze.rs ├── attr.rs ├── gen.rs ├── lib.rs └── proxy.rs └── tests ├── compile-fail ├── attr_on_enum.rs ├── attr_on_enum.stderr ├── attr_on_fn.rs ├── attr_on_fn.stderr ├── attr_on_impl_block.rs ├── attr_on_impl_block.stderr ├── attr_on_struct.rs ├── attr_on_struct.stderr ├── attr_on_type.rs ├── attr_on_type.stderr ├── attr_on_unit_struct.rs ├── attr_on_unit_struct.stderr ├── fn_associated_const.rs ├── fn_associated_const.stderr ├── fn_associated_type.rs ├── fn_associated_type.stderr ├── fn_const_generics.rs ├── fn_const_generics.stderr ├── fn_generics.rs ├── fn_generics.stderr ├── fn_multiple_methods.rs ├── fn_multiple_methods.stderr ├── fn_unsafe_method.rs ├── fn_unsafe_method.stderr ├── keep_default_for_on_assoc_type.rs ├── keep_default_for_on_assoc_type.stderr ├── keep_default_for_on_required_method.rs ├── keep_default_for_on_required_method.stderr ├── method_attr_invalid.rs ├── method_attr_invalid.stderr ├── mut_self_for_arc.rs ├── mut_self_for_arc.stderr ├── mut_self_for_immutable_ref.rs ├── mut_self_for_immutable_ref.stderr ├── mut_self_for_rc.rs ├── mut_self_for_rc.stderr ├── super_trait_not_implemented.rs ├── super_trait_not_implemented.stderr ├── trait_obj_value_self.rs ├── trait_obj_value_self.stderr ├── value_self_for_immutable_ref.rs ├── value_self_for_immutable_ref.stderr ├── value_self_for_mutable_ref.rs └── value_self_for_mutable_ref.stderr ├── compile-pass ├── associated_type_with_where_clause_for_all_refs.rs ├── big_trait_for_all_refs.rs ├── big_trait_for_box.rs ├── big_trait_where_bound_for_all_refs.rs ├── fn_method_lifetimes.rs ├── generic_fn_method_for_refs.rs ├── generic_types_and_lifetimes_for_fn.rs ├── generic_types_and_lifetimes_for_refs.rs ├── keep_default_for_simple.rs ├── keep_default_for_with_where_bounds.rs ├── method_name_shadowing.rs ├── mut_self_for_fn.rs ├── mut_self_for_fn_mut.rs ├── non_inferred_generic_types_for_all_refs.rs ├── non_inferred_generic_types_for_box.rs ├── non_inferred_generic_types_with_lifetimes_for_all_refs.rs ├── ref_self_for_fn.rs ├── self_bound.rs ├── self_bound_default_method.rs ├── self_bound_multiple.rs ├── self_by_value_mut.rs ├── super_trait_complex_for_refs.rs ├── super_trait_simple_for_fn_types.rs ├── super_trait_simple_for_refs.rs ├── trailing_comma.rs ├── trait_in_fn.rs ├── trait_in_mods.rs ├── trait_obj_default_method.rs ├── trait_obj_immutable_self.rs ├── trait_obj_self_sized.rs ├── trait_obj_value_self.rs ├── value_self_for_fn.rs ├── value_self_for_fn_mut.rs └── value_self_for_fn_once.rs ├── no_std.rs ├── since_1.51 └── compile-pass │ ├── associated_lifetime.rs │ ├── generic_const_method.rs │ └── generic_mix.rs ├── since_1.75 └── compile-pass │ └── async_trait.rs └── ui.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [pull_request, push] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | RUSTFLAGS: --deny warnings 8 | 9 | jobs: 10 | check: 11 | name: 'Build & test' 12 | runs-on: ubuntu-20.04 13 | strategy: 14 | matrix: 15 | rust-version: ['stable', 'beta', 'nightly', '1.56'] 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: dtolnay/rust-toolchain@master 19 | with: 20 | toolchain: stable 21 | components: rustfmt, clippy 22 | - uses: Swatinem/rust-cache@v1 23 | 24 | - run: cargo fmt --all -- --check 25 | - run: cargo clippy --workspace --all-features -- -D warnings 26 | - run: cargo test --workspace 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "auto_impl" 3 | version = "1.3.0" 4 | authors = [ 5 | "Ashley Mannix ", 6 | "Lukas Kalbertodt ", 7 | ] 8 | license = "MIT OR Apache-2.0" 9 | description = "Automatically implement traits for common smart pointers and closures" 10 | repository = "https://github.com/auto-impl-rs/auto_impl/" 11 | documentation = "https://docs.rs/auto_impl/" 12 | keywords = ["trait", "impl", "proc-macro", "closure"] 13 | categories = ["development-tools", "rust-patterns"] 14 | readme = "README.md" 15 | autotests = true 16 | edition = "2021" 17 | rust-version = "1.56" 18 | 19 | [workspace] 20 | members = [ 21 | "examples/async_await" 22 | ] 23 | 24 | [lib] 25 | proc-macro = true 26 | 27 | [dependencies] 28 | proc-macro2 = "1.0" 29 | quote = "1.0" 30 | syn = { version = "2.0", features = ["full", "visit", "visit-mut"] } 31 | 32 | [dev-dependencies] 33 | trybuild = "1" 34 | rustversion = "1" 35 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 auto_impl Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `auto_impl` [![CI](https://github.com/auto-impl-rs/auto_impl/actions/workflows/ci.yml/badge.svg)](https://github.com/auto-impl-rs/auto_impl/actions/workflows/ci.yml) [![Crates.io](https://img.shields.io/crates/v/auto_impl.svg)](https://crates.io/crates/auto_impl) [![docs](https://docs.rs/auto_impl/badge.svg)](https://docs.rs/auto_impl) 2 | 3 | A proc-macro attribute for automatically implementing a trait for references, 4 | some common smart pointers and closures. 5 | 6 | # Usage 7 | 8 | This library requires Rust 1.56.0 or newer. This library doesn't leave any public API in your code. 9 | 10 | Add `auto_impl` to your `Cargo.toml` and just use it in your crate: 11 | 12 | ```rust 13 | // In Rust 2015 you still need `extern crate auto_impl;` at your crate root 14 | use auto_impl::auto_impl; 15 | ``` 16 | 17 | Add an `auto_impl` attribute to traits you want to automatically implement for wrapper types. Here is a small example: 18 | 19 | ```rust 20 | // This will generate two additional impl blocks: one for `&T` and one 21 | // for `Box` where `T: Foo`. 22 | #[auto_impl(&, Box)] 23 | trait Foo { 24 | fn foo(&self); 25 | } 26 | 27 | impl Foo for i32 { 28 | fn foo(&self) {} 29 | } 30 | 31 | fn requires_foo(_: impl Foo) {} 32 | 33 | 34 | requires_foo(0i32); // works: through the impl we defined above 35 | requires_foo(&0i32); // works: through the generated impl 36 | requires_foo(Box::new(0i32)); // works: through the generated impl 37 | ``` 38 | 39 | For more explanations, please see [**the documentation**](https://docs.rs/auto_impl) and for more examples, see 40 | [the examples folder](https://github.com/auto-impl-rs/auto_impl/tree/master/examples). 41 | 42 | # Alternatives 43 | 44 | This library implements a fraction of a very broad and complex usecase. It's mostly useful for applications that 45 | define traits for components, and want to be able to abstract over the storage for those traits. If it doesn't offer 46 | some functionality you need, check out the [`impl-tools`](https://github.com/kas-gui/impl-tools/) project. 47 | 48 | --- 49 | 50 | ## License 51 | 52 | Licensed under either of 53 | 54 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 55 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 56 | 57 | at your option. 58 | 59 | ### Contribution 60 | 61 | Unless you explicitly state otherwise, any contribution intentionally submitted 62 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 63 | be dual licensed as above, without any additional terms or conditions. 64 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | - `error_messages`: contains some incorrect code that showcases the error messages emitted by `auto_impl` 4 | - **`greet_closure`**: simple example showing how to auto impl for `Fn` traits 5 | - **`keep_default_for`**: shows how to use the `#[auto_impl(keep_default_for(...))]` attribute 6 | - `names`: showcases how `auto_impl` chooses new ident names 7 | - **`refs`**: shows how to auto impl for `&` and `Box` 8 | 9 | 10 | **Note**: if you want to see what the generated impl blocks look like, use the execellent [`cargo expand`](https://github.com/dtolnay/cargo-expand): 11 | 12 | ``` 13 | $ cargo expand --example refs 14 | ``` 15 | -------------------------------------------------------------------------------- /examples/async_await/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "auto_impl_async_await_example" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [dependencies] 9 | auto_impl = { path = "../../" } 10 | async-trait = "0.1" 11 | async-std = { version = "1", features = ["attributes"] } 12 | -------------------------------------------------------------------------------- /examples/async_await/src/main.rs: -------------------------------------------------------------------------------- 1 | use async_std::task; 2 | use std::time::Duration; 3 | 4 | use async_trait::async_trait; 5 | use auto_impl::auto_impl; 6 | 7 | // Note the order of the attributes here: 8 | // `#[async_trait]` must appear first 9 | #[async_trait] 10 | #[auto_impl(&, Box, Arc)] 11 | trait Component { 12 | async fn run(&self); 13 | } 14 | 15 | struct WaitABit(Duration); 16 | 17 | #[async_trait] 18 | impl Component for WaitABit { 19 | async fn run(&self) { 20 | task::sleep(self.0).await; 21 | } 22 | } 23 | 24 | async fn run_async(a: impl Component) { 25 | a.run().await; 26 | } 27 | 28 | #[async_std::main] 29 | async fn main() { 30 | // We can treat our `Box` as an `impl Component` directly 31 | run_async(Box::new(WaitABit(Duration::from_secs(1)))).await; 32 | } 33 | -------------------------------------------------------------------------------- /examples/error_messages.rs: -------------------------------------------------------------------------------- 1 | //! This file showcases a few error messages emitted by `auto_impl`. You have 2 | //! to add specific lines to see the error. Then simply compile with: 3 | //! 4 | //! ``` 5 | //! cargo build --example error_messages 6 | //! ``` 7 | #![allow(unused_imports, dead_code)] 8 | 9 | use auto_impl::auto_impl; 10 | 11 | // Shows the error message for the case that `#[auto_impl]` was used with 12 | // incorrect proxy types. Only proxy types like `&` and `Box` are allowed. Add 13 | // this next line to see the error! 14 | //#[auto_impl(Boxxi)] 15 | trait Foo { 16 | fn foo(&self) -> u32; 17 | } 18 | 19 | // Shows the error message for the case the `#[auto_impl]` wasn't applied to a 20 | // valid trait (in this case a struct). Add this next line to see the error! 21 | //#[auto_impl(&, Box)] 22 | struct Bar { 23 | x: u32, 24 | } 25 | 26 | fn main() {} 27 | -------------------------------------------------------------------------------- /examples/greet_closure.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | /// This simple trait can be implemented for `Fn` types, but not for `FnMut` or 4 | /// `FnOnce` types. The latter two types require a mutable reference to `self` 5 | /// or a `self` by value to be called, but `greet()` only has an immutable 6 | /// reference. Try creating an auto-impl for `FnMut`: you should get an error. 7 | /// 8 | /// This attribute expands to the following impl (not exactly this code, but 9 | /// equivalent, slightly uglier code): 10 | /// 11 | /// ``` 12 | /// impl Greeter for F { 13 | /// fn greet(&self, name: &str) { 14 | /// self(name) 15 | /// } 16 | /// } 17 | /// ``` 18 | #[auto_impl(Fn)] 19 | trait Greeter { 20 | fn greet(&self, name: &str); 21 | } 22 | 23 | fn greet_people(greeter: impl Greeter) { 24 | greeter.greet("Anna"); 25 | greeter.greet("Bob"); 26 | } 27 | 28 | fn main() { 29 | // We can simply pass a closure here, since this specific closure 30 | // implements `Fn(&str)` and therefore also `Greeter`. Note that we need 31 | // explicit type annotations here. This has nothing to do with `auto_impl`, 32 | // but is simply a limitation of type inference. 33 | greet_people(|name: &str| println!("Hallo {} :)", name)); 34 | } 35 | -------------------------------------------------------------------------------- /examples/keep_default_for.rs: -------------------------------------------------------------------------------- 1 | //! Example to demonstrate how to use the `keep_default_for` attribute. 2 | //! 3 | //! The generated `impl` blocks generate an item for each trait item by 4 | //! default. This means that default methods in traits are also implemented via 5 | //! the proxy type. Sometimes, this is not what you want. One special case is 6 | //! when the default method has where bounds that don't apply to the proxy 7 | //! type. 8 | use auto_impl::auto_impl; 9 | 10 | #[auto_impl(&, Box)] 11 | trait Foo { 12 | fn required(&self) -> String; 13 | 14 | // The generated impl for `&T` will not override this method. 15 | #[auto_impl(keep_default_for(&))] 16 | fn provided(&self) { 17 | println!("Hello {}", self.required()); 18 | } 19 | } 20 | 21 | impl Foo for String { 22 | fn required(&self) -> String { 23 | self.clone() 24 | } 25 | 26 | fn provided(&self) { 27 | println!("привет {}", self); 28 | } 29 | } 30 | 31 | fn test_foo(x: impl Foo) { 32 | x.provided(); 33 | } 34 | 35 | fn main() { 36 | let s = String::from("Peter"); 37 | 38 | // Output: "привет Peter", because `String` has overwritten the default 39 | // method. 40 | test_foo(s.clone()); 41 | 42 | // Output: "Hello Peter", because the method is not overwritten for the 43 | // `&T` impl block. 44 | test_foo(&s); 45 | 46 | // Output: "привет Peter", because the `Box` impl overwrites the method 47 | // by default, if you don't specify `keep_default_for`. 48 | test_foo(Box::new(s)); 49 | } 50 | -------------------------------------------------------------------------------- /examples/names.rs: -------------------------------------------------------------------------------- 1 | //! Example to demonstrate how `auto_impl` chooses a name for the type and 2 | //! lifetime parameter. 3 | //! 4 | //! For documentation and compiler errors it would be nice to have very simple 5 | //! names for type and lifetime parameters: 6 | //! 7 | //! ```rust 8 | //! // not nice 9 | //! impl<'auto_impl_lifetime, AutoImplT> Foo for &'auto_impl_lifetime AutoImplT { ...} 10 | //! 11 | //! // better 12 | //! impl<'a, T> Foo for &'a T { ... } 13 | //! ``` 14 | //! 15 | //! `auto_impl` tries the full alphabet, picking a name that is not yet taken. 16 | //! "Not taken" means that the name is not used anywhere in the `impl` block. 17 | //! Right now, we are a bit careful and mark all names as "taken" that are used 18 | //! in the trait def -- apart from names only appearing in the body of provided 19 | //! methods. 20 | //! 21 | //! In the trait below, a bunch of names are already "taken": 22 | //! - type names: T--Z and A--G (H is not taken, because it only appear in the 23 | //! default method body) 24 | //! - lifetime names: 'a--'c 25 | //! 26 | //! Thus, the names `H` and `'d` are used. Run `cargo expand --example names` 27 | //! to see the output. 28 | 29 | 30 | // This code is really ugly on purpose... 31 | #![allow(non_snake_case, dead_code, unused_variables, clippy::extra_unused_lifetimes, clippy::let_unit_value, clippy::redundant_allocation)] 32 | #![cfg_attr(rustfmt, rustfmt::skip)] 33 | 34 | use auto_impl::auto_impl; 35 | 36 | 37 | 38 | struct X {} 39 | trait Z {} 40 | 41 | struct C {} 42 | struct E(Vec); 43 | struct F {} 44 | 45 | struct G(Vec); 46 | struct H {} 47 | 48 | #[auto_impl(&)] 49 | trait U<'a, V> { 50 | const W: Option>; 51 | 52 | type Y: Z; 53 | 54 | fn A<'b, 'c>(&self, B: C, D: E<&[F; 1]>) -> G { 55 | let H = (); 56 | unimplemented!() 57 | } 58 | } 59 | 60 | fn main() {} 61 | -------------------------------------------------------------------------------- /examples/refs.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use auto_impl::auto_impl; 4 | 5 | /// This trait can be implemented for all reference or pointer types: &, &mut, 6 | /// Box, Rc and Arc. 7 | /// 8 | /// This attribute expands to the following impl (not exactly this code, but 9 | /// equivalent, slightly uglier code): 10 | /// 11 | /// ``` 12 | /// impl<'a, T: 'a + DisplayCollection> DisplayCollection for &'a T { 13 | /// type Out = T::Out; 14 | /// fn display_at(&self, index: usize) -> Option<&Self::Out> { 15 | /// (**self).display_at(index) 16 | /// } 17 | /// } 18 | /// 19 | /// impl DisplayCollection for Box { 20 | /// type Out = T::Out; 21 | /// fn display_at(&self, index: usize) -> Option<&Self::Out> { 22 | /// (**self).display_at(index) 23 | /// } 24 | /// } 25 | /// ``` 26 | #[auto_impl(&, Box)] 27 | trait DisplayCollection { 28 | /// If the length is statically known, this is `Some(len)`. 29 | const LEN: Option; 30 | type Out: Display; 31 | fn display_at(&self, index: usize) -> Option<&Self::Out>; 32 | } 33 | 34 | impl DisplayCollection for Vec { 35 | type Out = T; 36 | 37 | const LEN: Option = None; 38 | 39 | fn display_at(&self, index: usize) -> Option<&Self::Out> { 40 | self.get(index) 41 | } 42 | } 43 | 44 | fn show_first(c: impl DisplayCollection) { 45 | match c.display_at(0) { 46 | Some(x) => println!("First: {}", x), 47 | None => println!("Nothing :/"), 48 | } 49 | } 50 | 51 | #[allow(clippy::needless_borrow)] 52 | #[rustfmt::skip] 53 | fn main() { 54 | let v = vec!["dog", "cat"]; 55 | let boxed = Box::new(v.clone()); 56 | 57 | show_first(v.clone()); // Vec<&str> (our manual impl) 58 | show_first(&v); // &Vec<&str> (auto-impl) 59 | show_first(&&v); // &&Vec<&str> (works too, of course) 60 | show_first(boxed.clone()); // Box> (auto-impl) 61 | show_first(&boxed); // &Box> 62 | } 63 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | unstable_features = true 2 | 3 | blank_lines_upper_bound = 3 4 | format_macro_matchers = true 5 | imports_granularity="Crate" 6 | normalize_comments = true 7 | reorder_impl_items = true 8 | -------------------------------------------------------------------------------- /src/analyze.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | use proc_macro2::Span as Span2; 4 | use syn::{ 5 | visit::{visit_item_trait, Visit}, 6 | Block, Ident, ItemTrait, Lifetime, 7 | }; 8 | 9 | /// The type parameter used in the proxy type. Usually, one would just use `T`, 10 | /// but this could conflict with type parameters on the trait. 11 | /// 12 | /// Why do we have to care about this? Why about hygiene? In the first version 13 | /// of stable proc_macros, only call site spans are included. That means that 14 | /// we cannot generate spans that do not conflict with any other ident the user 15 | /// wrote. Once proper hygiene is available to proc_macros, this should be 16 | /// changed. 17 | const PROXY_TY_PARAM_NAME: &str = "__AutoImplProxyT"; 18 | 19 | /// The lifetime parameter used in the proxy type if the proxy type is `&` or 20 | /// `&mut`. For more information see `PROXY_TY_PARAM_NAME`. 21 | const PROXY_LT_PARAM_NAME: &str = "'__auto_impl_proxy_lifetime"; 22 | 23 | /// We need to introduce our own type and lifetime parameter. Regardless of 24 | /// what kind of hygiene we use for the parameter, it would be nice (for docs 25 | /// and compiler errors) if the names are as simple as possible ('a and T, for 26 | /// example). 27 | /// 28 | /// This function searches for names that we can use. Such a name must not 29 | /// conflict with any other name we'll use in the `impl` block. Luckily, we 30 | /// know all those names in advance. 31 | /// 32 | /// The idea is to collect all names that might conflict with our names, store 33 | /// them in a set and later check which name we can use. If we can't use a simple 34 | /// name, we'll use the ugly `PROXY_TY_PARAM_NAME` and `PROXY_LT_PARAM_NAME`. 35 | /// 36 | /// This method returns two idents: (type_parameter, lifetime_parameter). 37 | pub(crate) fn find_suitable_param_names(trait_def: &ItemTrait) -> (Ident, Lifetime) { 38 | // Define the visitor that just collects names 39 | struct IdentCollector<'ast> { 40 | ty_names: HashSet<&'ast Ident>, 41 | lt_names: HashSet<&'ast Ident>, 42 | } 43 | 44 | impl<'ast> Visit<'ast> for IdentCollector<'ast> { 45 | fn visit_ident(&mut self, i: &'ast Ident) { 46 | self.ty_names.insert(i); 47 | } 48 | 49 | // We overwrite this to make sure to put lifetime names into 50 | // `lt_names`. We also don't recurse, so `visit_ident` won't be called 51 | // for lifetime names. 52 | fn visit_lifetime(&mut self, lt: &'ast Lifetime) { 53 | self.lt_names.insert(<.ident); 54 | } 55 | 56 | // Visiting a block just does nothing. It is the default body of a method 57 | // in the trait. But since that block won't be in the impl block, we can 58 | // just ignore it. 59 | fn visit_block(&mut self, _: &'ast Block) {} 60 | } 61 | 62 | // Create the visitor and visit the trait 63 | let mut visitor = IdentCollector { 64 | ty_names: HashSet::new(), 65 | lt_names: HashSet::new(), 66 | }; 67 | visit_item_trait(&mut visitor, trait_def); 68 | 69 | fn char_to_ident(c: u8) -> Ident { 70 | let arr = [c]; 71 | let s = ::std::str::from_utf8(&arr).unwrap(); 72 | Ident::new(s, param_span()) 73 | } 74 | 75 | // Find suitable type name (T..=Z and A..=S) 76 | let ty_name = (b'T'..=b'Z') 77 | .chain(b'A'..=b'S') 78 | .map(char_to_ident) 79 | .find(|i| !visitor.ty_names.contains(i)) 80 | .unwrap_or_else(|| Ident::new(PROXY_TY_PARAM_NAME, param_span())); 81 | 82 | // Find suitable lifetime name ('a..='z) 83 | let lt_name = (b'a'..=b'z') 84 | .map(char_to_ident) 85 | .find(|i| !visitor.lt_names.contains(i)) 86 | .unwrap_or_else(|| Ident::new(PROXY_LT_PARAM_NAME, param_span())); 87 | let lt = Lifetime { 88 | apostrophe: param_span(), 89 | ident: lt_name, 90 | }; 91 | 92 | (ty_name, lt) 93 | } 94 | 95 | fn param_span() -> Span2 { 96 | Span2::call_site() 97 | } 98 | -------------------------------------------------------------------------------- /src/attr.rs: -------------------------------------------------------------------------------- 1 | //! Internal attributes of the form `#[auto_impl(name(...))]` that can be 2 | //! attached to trait items. 3 | 4 | use proc_macro2::{Delimiter, TokenTree}; 5 | use syn::{ 6 | spanned::Spanned, 7 | visit_mut::{visit_item_trait_mut, VisitMut}, 8 | Attribute, Error, Meta, TraitItem, 9 | }; 10 | 11 | use crate::proxy::{parse_types, ProxyType}; 12 | 13 | /// Removes all `#[auto_impl]` attributes that are attached to methods of the 14 | /// given trait. 15 | pub(crate) fn remove_our_attrs(trait_def: &mut syn::ItemTrait) -> syn::Result<()> { 16 | struct AttrRemover(syn::Result<()>); 17 | impl VisitMut for AttrRemover { 18 | fn visit_trait_item_mut(&mut self, item: &mut TraitItem) { 19 | let item_span = item.span(); 20 | let (attrs, is_method) = match item { 21 | TraitItem::Fn(m) => (&mut m.attrs, true), 22 | TraitItem::Const(c) => (&mut c.attrs, false), 23 | TraitItem::Type(t) => (&mut t.attrs, false), 24 | TraitItem::Macro(m) => (&mut m.attrs, false), 25 | _ => { 26 | let err = syn::Error::new( 27 | item.span(), 28 | "encountered unexpected `TraitItem`, cannot handle that, sorry!", 29 | ); 30 | 31 | if let Err(ref mut current_err) = self.0 { 32 | current_err.combine(err); 33 | } else { 34 | self.0 = Err(err); 35 | }; 36 | 37 | return; 38 | } 39 | }; 40 | 41 | // Make sure non-methods do not have our attributes. 42 | if !is_method && attrs.iter().any(is_our_attr) { 43 | let err = syn::Error::new( 44 | item_span, 45 | "`#[auto_impl]` attributes are only allowed on methods", 46 | ); 47 | 48 | if let Err(ref mut current_err) = self.0 { 49 | current_err.combine(err); 50 | } else { 51 | self.0 = Err(err); 52 | }; 53 | 54 | return; 55 | } 56 | 57 | attrs.retain(|a| !is_our_attr(a)); 58 | } 59 | } 60 | 61 | let mut visitor = AttrRemover(Ok(())); 62 | visit_item_trait_mut(&mut visitor, trait_def); 63 | 64 | visitor.0 65 | } 66 | 67 | /// Checks if the given attribute is "our" attribute. That means that it's path 68 | /// is `auto_impl`. 69 | pub(crate) fn is_our_attr(attr: &Attribute) -> bool { 70 | attr.path().is_ident("auto_impl") 71 | } 72 | 73 | /// Tries to parse the given attribute as one of our own `auto_impl` 74 | /// attributes. If it's invalid, an error is emitted and `Err(())` is returned. 75 | /// You have to make sure that `attr` is one of our attrs with `is_our_attr` 76 | /// before calling this function! 77 | pub(crate) fn parse_our_attr(attr: &Attribute) -> syn::Result { 78 | assert!(is_our_attr(attr)); 79 | 80 | // Get the body of the attribute (which has to be a ground, because we 81 | // required the syntax `auto_impl(...)` and forbid stuff like 82 | // `auto_impl = ...`). 83 | let body = match &attr.meta { 84 | Meta::List(list) => list.tokens.clone(), 85 | _ => { 86 | return Err(Error::new( 87 | attr.span(), 88 | "expected single group delimited by `()`", 89 | )); 90 | } 91 | }; 92 | 93 | let mut it = body.clone().into_iter(); 94 | 95 | // Try to extract the name (we require the body to be `name(...)`). 96 | let name = match it.next() { 97 | Some(TokenTree::Ident(x)) => x, 98 | Some(other) => { 99 | return Err(Error::new( 100 | other.span(), 101 | format_args!("expected ident, found '{}'", other), 102 | )); 103 | } 104 | None => { 105 | return Err(Error::new(attr.span(), "expected ident, found nothing")); 106 | } 107 | }; 108 | 109 | // Extract the parameters (which again, have to be a group delimited by 110 | // `()`) 111 | let params = match it.next() { 112 | Some(TokenTree::Group(ref g)) if g.delimiter() == Delimiter::Parenthesis => g.stream(), 113 | Some(other) => { 114 | return Err(Error::new( 115 | other.span(), 116 | format_args!( 117 | "expected arguments for '{}' in parenthesis `()`, found `{}`", 118 | name, other 119 | ), 120 | )); 121 | } 122 | None => { 123 | return Err(Error::new( 124 | body.span(), 125 | format_args!( 126 | "expected arguments for '{}' in parenthesis `()`, found nothing", 127 | name, 128 | ), 129 | )); 130 | } 131 | }; 132 | 133 | // Finally match over the name of the attribute. 134 | let out = if name == "keep_default_for" { 135 | let proxy_types = parse_types(params.into()); 136 | OurAttr::KeepDefaultFor(proxy_types) 137 | } else { 138 | return Err(Error::new( 139 | name.span(), 140 | format_args!( 141 | "invalid attribute '{}'; only `keep_default_for` is supported", 142 | name 143 | ), 144 | )); 145 | }; 146 | 147 | Ok(out) 148 | } 149 | 150 | /// Attributes of the form `#[auto_impl(...)]` that can be attached to items of 151 | /// the trait. 152 | #[derive(Clone, PartialEq, Debug)] 153 | pub(crate) enum OurAttr { 154 | KeepDefaultFor(Vec), 155 | } 156 | -------------------------------------------------------------------------------- /src/gen.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Span as Span2, TokenStream as TokenStream2, TokenTree as TokenTree2}; 2 | use quote::{ToTokens, TokenStreamExt}; 3 | use syn::{ 4 | punctuated::Punctuated, spanned::Spanned, Attribute, Error, FnArg, GenericParam, Ident, 5 | ItemTrait, Lifetime, Pat, PatIdent, PatType, ReturnType, Signature, Token, TraitBound, 6 | TraitBoundModifier, TraitItem, TraitItemConst, TraitItemFn, TraitItemType, Type, 7 | TypeParamBound, WherePredicate, 8 | }; 9 | 10 | use crate::{ 11 | analyze::find_suitable_param_names, 12 | attr::{is_our_attr, parse_our_attr, OurAttr}, 13 | proxy::ProxyType, 14 | }; 15 | 16 | /// Generates one complete impl of the given trait for each of the given proxy 17 | /// types. All impls are returned as token stream. 18 | pub(crate) fn gen_impls( 19 | proxy_types: &[ProxyType], 20 | trait_def: &syn::ItemTrait, 21 | ) -> syn::Result { 22 | let mut tokens = TokenStream2::new(); 23 | 24 | let (proxy_ty_param, proxy_lt_param) = find_suitable_param_names(trait_def); 25 | 26 | // One impl for each proxy type 27 | for proxy_type in proxy_types { 28 | let header = gen_header(proxy_type, trait_def, &proxy_ty_param, &proxy_lt_param)?; 29 | let items = gen_items(proxy_type, trait_def, &proxy_ty_param)?; 30 | 31 | if let ProxyType::Box | ProxyType::Rc | ProxyType::Arc = proxy_type { 32 | tokens.append_all(quote! { 33 | const _: () = { 34 | extern crate alloc; 35 | #header { #( #items )* } 36 | }; 37 | }); 38 | } else { 39 | tokens.append_all(quote! { 40 | const _: () = { 41 | #header { #( #items )* } 42 | }; 43 | }); 44 | } 45 | } 46 | 47 | Ok(tokens) 48 | } 49 | 50 | /// Generates the header of the impl of the given trait for the given proxy 51 | /// type. 52 | fn gen_header( 53 | proxy_type: &ProxyType, 54 | trait_def: &ItemTrait, 55 | proxy_ty_param: &Ident, 56 | proxy_lt_param: &Lifetime, 57 | ) -> syn::Result { 58 | // Generate generics for impl positions from trait generics. 59 | let (impl_generics, trait_generics, where_clause) = trait_def.generics.split_for_impl(); 60 | 61 | // The name of the trait with all generic parameters applied. 62 | let trait_ident = &trait_def.ident; 63 | let trait_path = quote! { #trait_ident #trait_generics }; 64 | 65 | // Here we assemble the parameter list of the impl (the thing in 66 | // `impl< ... >`). This is simply the parameter list of the trait with 67 | // one or two parameters added. For a trait `trait Foo<'x, 'y, A, B>`, 68 | // it will look like this: 69 | // 70 | // '{proxy_lt_param}, 'x, 'y, A, B, {proxy_ty_param} 71 | // 72 | // The `'{proxy_lt_param}` in the beginning is only added when the proxy 73 | // type is `&` or `&mut`. 74 | let impl_generics = { 75 | // Determine whether we can add a `?Sized` relaxation to allow trait 76 | // objects. We can do that as long as there is no method that has a 77 | // `self` by value receiver and no `where Self: Sized` bound. 78 | let methods = trait_def 79 | .items 80 | .iter() 81 | // Only interested in methods 82 | .filter_map(|item| { 83 | if let TraitItem::Fn(m) = item { 84 | Some(m) 85 | } else { 86 | None 87 | } 88 | }); 89 | 90 | let mut sized_required = false; 91 | for m in methods { 92 | if should_keep_default_for(m, proxy_type)? { 93 | continue; 94 | } 95 | 96 | // Check if there is a `Self: Sized` bound on the method. 97 | let self_is_bounded_sized = m 98 | .sig 99 | .generics 100 | .where_clause 101 | .iter() 102 | .flat_map(|wc| &wc.predicates) 103 | .filter_map(|pred| { 104 | if let WherePredicate::Type(p) = pred { 105 | Some(p) 106 | } else { 107 | None 108 | } 109 | }) 110 | .any(|pred| { 111 | // Check if the type is `Self` 112 | match &pred.bounded_ty { 113 | Type::Path(p) if p.path.is_ident("Self") => { 114 | // Check if the bound contains `Sized` 115 | pred.bounds.iter().any(|b| match b { 116 | TypeParamBound::Trait(TraitBound { 117 | modifier: TraitBoundModifier::None, 118 | path, 119 | .. 120 | }) => path.is_ident("Sized"), 121 | _ => false, 122 | }) 123 | } 124 | _ => false, 125 | } 126 | }); 127 | 128 | // Check if the first parameter is `self` by value. In that 129 | // case, we might require `Self` to be `Sized`. 130 | let self_value_param = match m.sig.inputs.first() { 131 | Some(FnArg::Receiver(receiver)) => receiver.reference.is_none(), 132 | _ => false, 133 | }; 134 | 135 | // Check if return type is `Self` 136 | let self_value_return = match &m.sig.output { 137 | ReturnType::Type(_, t) => { 138 | if let Type::Path(p) = &**t { 139 | p.path.is_ident("Self") 140 | } else { 141 | false 142 | } 143 | } 144 | _ => false, 145 | }; 146 | 147 | // TODO: check for `Self` parameter in any other argument. 148 | 149 | // If for this method, `Self` is used in a position that 150 | // requires `Self: Sized` or this bound is added explicitly, we 151 | // cannot add the `?Sized` relaxation to the impl body. 152 | if self_value_param || self_value_return || self_is_bounded_sized { 153 | sized_required = true; 154 | break; 155 | } 156 | } 157 | 158 | let relaxation = if sized_required { 159 | quote! {} 160 | } else { 161 | quote! { + ?::core::marker::Sized } 162 | }; 163 | 164 | // Check if there are some `Self: Foo` bounds on methods. If so, we 165 | // need to add those bounds to `T` as well. See issue #11 for more 166 | // information, but in short: there is no better solution. Method where 167 | // clauses with `Self: Foo` force us to add `T: Foo` to the impl 168 | // header, as we otherwise cannot generate a valid impl block. 169 | let methods = trait_def 170 | .items 171 | .iter() 172 | // Only interested in methods 173 | .filter_map(|item| { 174 | if let TraitItem::Fn(m) = item { 175 | Some(m) 176 | } else { 177 | None 178 | } 179 | }); 180 | 181 | let mut additional_bounds = Vec::new(); 182 | for m in methods { 183 | if should_keep_default_for(m, proxy_type)? { 184 | continue; 185 | } 186 | 187 | additional_bounds.extend( 188 | m.sig 189 | .generics 190 | .where_clause 191 | .iter() 192 | .flat_map(|wc| &wc.predicates) 193 | .filter_map(|pred| { 194 | if let WherePredicate::Type(p) = pred { 195 | Some(p) 196 | } else { 197 | None 198 | } 199 | }) 200 | .filter(|p| { 201 | // Only `Self:` bounds 202 | match &p.bounded_ty { 203 | Type::Path(p) => p.path.is_ident("Self"), 204 | _ => false, 205 | } 206 | }) 207 | .flat_map(|p| &p.bounds) 208 | .filter_map(|b| { 209 | // We are only interested in trait bounds. That's 210 | // because lifetime bounds on `Self` do not need to be 211 | // added to the impl header. That's because all values 212 | // "derived" from `self` also meet the same lifetime 213 | // bound as `self`. In simpler terms: while `self.field` 214 | // might not be `Clone` even if `Self: Clone`, 215 | // `self.field` is always `: 'a` if `Self: 'a`. 216 | match b { 217 | TypeParamBound::Trait(t) => Some(t), 218 | _ => None, 219 | } 220 | }), 221 | ); 222 | } 223 | 224 | // Determine if our proxy type needs a lifetime parameter 225 | let (mut params, ty_bounds) = match proxy_type { 226 | ProxyType::Ref | ProxyType::RefMut => ( 227 | quote! { #proxy_lt_param, }, 228 | quote! { : #proxy_lt_param + #trait_path #relaxation #(+ #additional_bounds)* }, 229 | ), 230 | ProxyType::Box | ProxyType::Rc | ProxyType::Arc => ( 231 | quote! {}, 232 | quote! { : #trait_path #relaxation #(+ #additional_bounds)* }, 233 | ), 234 | ProxyType::Fn | ProxyType::FnMut | ProxyType::FnOnce => { 235 | let fn_bound = gen_fn_type_for_trait(proxy_type, trait_def)?; 236 | (quote! {}, quote! { : #fn_bound }) 237 | } 238 | }; 239 | 240 | // Append all parameters from the trait. Sadly, `impl_generics` 241 | // includes the angle brackets `< >` so we have to remove them like 242 | // this. 243 | let mut tts = impl_generics 244 | .into_token_stream() 245 | .into_iter() 246 | .skip(1) // the opening `<` 247 | .collect::>(); 248 | tts.pop(); // the closing `>` 249 | 250 | // Pop a trailing comma if there is one 251 | // We'll end up conditionally putting one back in shortly 252 | if tts.last().and_then(|tt| { 253 | if let TokenTree2::Punct(p) = tt { 254 | Some(p.as_char()) 255 | } else { 256 | None 257 | } 258 | }) == Some(',') 259 | { 260 | tts.pop(); 261 | } 262 | 263 | params.append_all(&tts); 264 | 265 | // Append proxy type parameter (if there aren't any parameters so far, 266 | // we need to add a comma first). 267 | let comma = if params.is_empty() || tts.is_empty() { 268 | quote! {} 269 | } else { 270 | quote! { , } 271 | }; 272 | params.append_all(quote! { #comma #proxy_ty_param #ty_bounds }); 273 | 274 | params 275 | }; 276 | 277 | // The tokens after `for` in the impl header (the type the trait is 278 | // implemented for). 279 | #[rustfmt::skip] 280 | let self_ty = match *proxy_type { 281 | ProxyType::Ref => quote! { & #proxy_lt_param #proxy_ty_param }, 282 | ProxyType::RefMut => quote! { & #proxy_lt_param mut #proxy_ty_param }, 283 | ProxyType::Arc => quote! { alloc::sync::Arc<#proxy_ty_param> }, 284 | ProxyType::Rc => quote! { alloc::rc::Rc<#proxy_ty_param> }, 285 | ProxyType::Box => quote! { alloc::boxed::Box<#proxy_ty_param> }, 286 | ProxyType::Fn => quote! { #proxy_ty_param }, 287 | ProxyType::FnMut => quote! { #proxy_ty_param }, 288 | ProxyType::FnOnce => quote! { #proxy_ty_param }, 289 | }; 290 | 291 | // If the trait has super traits, we need to add the super trait bound to 292 | // our self type. This can only be done in the where clause, so we need to 293 | // combine the existing where clauses with our new predicate in that case. 294 | let where_clause = if !trait_def.supertraits.is_empty() { 295 | let mut out = quote! { where }; 296 | 297 | if !trait_def.supertraits.is_empty() { 298 | let supertraits = &trait_def.supertraits; 299 | out.extend(quote! { #self_ty: #supertraits, }); 300 | } 301 | if let Some(predicates) = where_clause.map(|c| &c.predicates) { 302 | out.extend(predicates.into_token_stream()); 303 | } 304 | 305 | out 306 | } else { 307 | where_clause.into_token_stream() 308 | }; 309 | 310 | // Combine everything 311 | Ok(quote! { 312 | impl<#impl_generics> #trait_path for #self_ty #where_clause 313 | }) 314 | } 315 | 316 | /// Generates the Fn-trait type (e.g. `FnMut(u32) -> String`) for the given 317 | /// trait and proxy type (the latter has to be `Fn`, `FnMut` or `FnOnce`!) 318 | /// 319 | /// If the trait is unsuitable to be implemented for the given proxy type, an 320 | /// error is emitted. 321 | fn gen_fn_type_for_trait( 322 | proxy_type: &ProxyType, 323 | trait_def: &ItemTrait, 324 | ) -> syn::Result { 325 | // Only traits with exactly one method can be implemented for Fn-traits. 326 | // Associated types and consts are also not allowed. 327 | let method = trait_def.items.first().and_then(|item| { 328 | if let TraitItem::Fn(m) = item { 329 | Some(m) 330 | } else { 331 | None 332 | } 333 | }); 334 | 335 | // If this requirement is not satisfied, we emit an error. 336 | if method.is_none() || trait_def.items.len() > 1 { 337 | return Err(Error::new( 338 | trait_def.span(), 339 | "this trait cannot be auto-implemented for Fn-traits (only traits with exactly \ 340 | one method and no other items are allowed)", 341 | )); 342 | } 343 | 344 | // We checked for `None` above 345 | let method = method.unwrap(); 346 | let sig = &method.sig; 347 | 348 | // Check for forbidden modifier of the method 349 | if let Some(const_token) = sig.constness { 350 | return Err(Error::new( 351 | const_token.span(), 352 | format_args!( 353 | "the trait '{}' cannot be auto-implemented for Fn-traits: const methods are not \ 354 | allowed", 355 | trait_def.ident 356 | ), 357 | )); 358 | } 359 | 360 | if let Some(unsafe_token) = &sig.unsafety { 361 | return Err(Error::new( 362 | unsafe_token.span(), 363 | format_args!( 364 | "the trait '{}' cannot be auto-implemented for Fn-traits: unsafe methods are not \ 365 | allowed", 366 | trait_def.ident 367 | ), 368 | )); 369 | } 370 | 371 | if let Some(abi_token) = &sig.abi { 372 | return Err(Error::new( 373 | abi_token.span(), 374 | format_args!( 375 | "the trait '{}' cannot be implemented for Fn-traits: custom ABIs are not allowed", 376 | trait_def.ident 377 | ), 378 | )); 379 | } 380 | 381 | // Function traits cannot support generics in their arguments 382 | // These would require HRTB for types instead of just lifetimes 383 | let mut r: syn::Result<()> = Ok(()); 384 | for type_param in sig.generics.type_params() { 385 | let err = Error::new( 386 | type_param.span(), 387 | format_args!("the trait '{}' cannot be implemented for Fn-traits: generic arguments are not allowed", 388 | trait_def.ident), 389 | ); 390 | 391 | if let Err(ref mut current_err) = r { 392 | current_err.combine(err); 393 | } else { 394 | r = Err(err); 395 | } 396 | } 397 | 398 | for const_param in sig.generics.const_params() { 399 | let err = Error::new( 400 | const_param.span(), 401 | format_args!("the trait '{}' cannot be implemented for Fn-traits: constant arguments are not allowed", 402 | trait_def.ident), 403 | ); 404 | 405 | if let Err(ref mut current_err) = r { 406 | current_err.combine(err); 407 | } else { 408 | r = Err(err); 409 | } 410 | } 411 | r?; 412 | 413 | // ======================================================================= 414 | // Check if the trait can be implemented for the given proxy type 415 | let self_type = SelfType::from_sig(sig); 416 | let err = match (self_type, proxy_type) { 417 | // The method needs to have a receiver 418 | (SelfType::None, _) => Some(("Fn-traits", "no", "")), 419 | 420 | // We can't impl methods with `&mut self` or `&self` receiver for 421 | // `FnOnce` 422 | (SelfType::Mut, ProxyType::FnOnce) => { 423 | Some(("`FnOnce`", "a `&mut self`", " (only `self` is allowed)")) 424 | } 425 | (SelfType::Ref, ProxyType::FnOnce) => { 426 | Some(("`FnOnce`", "a `&self`", " (only `self` is allowed)")) 427 | } 428 | 429 | // We can't impl methods with `&self` receiver for `FnMut` 430 | (SelfType::Ref, ProxyType::FnMut) => Some(( 431 | "`FnMut`", 432 | "a `&self`", 433 | " (only `self` and `&mut self` are allowed)", 434 | )), 435 | 436 | // Other combinations are fine 437 | _ => None, 438 | }; 439 | 440 | if let Some((fn_traits, receiver, allowed)) = err { 441 | return Err(Error::new( 442 | method.sig.span(), 443 | format_args!( 444 | "the trait '{}' cannot be auto-implemented for {}, because this method has \ 445 | {} receiver{}", 446 | trait_def.ident, fn_traits, receiver, allowed, 447 | ), 448 | )); 449 | } 450 | 451 | // ======================================================================= 452 | // Generate the full Fn-type 453 | 454 | // The path to the Fn-trait 455 | let fn_name = match proxy_type { 456 | ProxyType::Fn => quote! { ::core::ops::Fn }, 457 | ProxyType::FnMut => quote! { ::core::ops::FnMut }, 458 | ProxyType::FnOnce => quote! { ::core::ops::FnOnce }, 459 | _ => panic!("internal error in auto_impl (function contract violation)"), 460 | }; 461 | 462 | // The return type 463 | let ret = &sig.output; 464 | 465 | // Now it gets a bit complicated. The types of the function signature 466 | // could contain "local" lifetimes, meaning that they are not declared in 467 | // the trait definition (or are `'static`). We need to extract all local 468 | // lifetimes to declare them with HRTB (e.g. `for<'a>`). 469 | // 470 | // In Rust 2015 that was easy: we could just take the lifetimes explicitly 471 | // declared in the function signature. Those were the local lifetimes. 472 | // Unfortunately, with in-band lifetimes, things get more complicated. We 473 | // need to take a look at all lifetimes inside the types (arbitrarily deep) 474 | // and check if they are local or not. 475 | // 476 | // In cases where lifetimes are omitted (e.g. `&str`), we don't have a 477 | // problem. If we just translate that to `for<> Fn(&str)`, it's fine: all 478 | // omitted lifetimes in an `Fn()` type are automatically declared as HRTB. 479 | // 480 | // TODO: Implement this check for in-band lifetimes! 481 | let local_lifetimes = sig.generics.lifetimes(); 482 | 483 | // The input types as comma separated list. We skip the first argument, as 484 | // this is the receiver argument. 485 | let mut arg_types = TokenStream2::new(); 486 | for arg in sig.inputs.iter().skip(1) { 487 | match arg { 488 | FnArg::Typed(pat) => { 489 | let ty = &pat.ty; 490 | arg_types.append_all(quote! { #ty , }); 491 | } 492 | 493 | // We skipped the receiver already. 494 | FnArg::Receiver(r) => { 495 | return Err(Error::new( 496 | r.span(), 497 | "receiver argument that's not the first argument (auto_impl is confused)", 498 | )); 499 | } 500 | } 501 | } 502 | 503 | Ok(quote! { 504 | for< #(#local_lifetimes),* > #fn_name (#arg_types) #ret 505 | }) 506 | } 507 | 508 | /// Generates the implementation of all items of the given trait. These 509 | /// implementations together are the body of the `impl` block. 510 | fn gen_items( 511 | proxy_type: &ProxyType, 512 | trait_def: &ItemTrait, 513 | proxy_ty_param: &Ident, 514 | ) -> syn::Result> { 515 | trait_def 516 | .items 517 | .iter() 518 | .map(|item| { 519 | match item { 520 | TraitItem::Const(c) => gen_const_item(proxy_type, c, trait_def, proxy_ty_param), 521 | TraitItem::Fn(method) => { 522 | gen_method_item(proxy_type, method, trait_def, proxy_ty_param) 523 | } 524 | TraitItem::Type(ty) => gen_type_item(proxy_type, ty, trait_def, proxy_ty_param), 525 | TraitItem::Macro(mac) => { 526 | // We cannot resolve the macro invocation and thus cannot know 527 | // if it adds additional items to the trait. Thus, we have to 528 | // give up. 529 | Err(Error::new( 530 | mac.span(), 531 | "traits with macro invocations in their bodies are not \ 532 | supported by auto_impl", 533 | )) 534 | } 535 | TraitItem::Verbatim(v) => { 536 | // I don't quite know when this happens, but it's better to 537 | // notify the user with a nice error instead of panicking. 538 | Err(Error::new( 539 | v.span(), 540 | "unexpected 'verbatim'-item (auto-impl doesn't know how to handle it)", 541 | )) 542 | } 543 | _ => { 544 | // `syn` enums are `non_exhaustive` to be future-proof. If a 545 | // trait contains a kind of item we don't even know about, we 546 | // emit an error. 547 | Err(Error::new( 548 | item.span(), 549 | "unknown trait item (auto-impl doesn't know how to handle it)", 550 | )) 551 | } 552 | } 553 | }) 554 | .collect() 555 | } 556 | 557 | /// Generates the implementation of an associated const item described by 558 | /// `item`. The implementation is returned as token stream. 559 | /// 560 | /// If the proxy type is an Fn*-trait, an error is emitted and `Err(())` is 561 | /// returned. 562 | fn gen_const_item( 563 | proxy_type: &ProxyType, 564 | item: &TraitItemConst, 565 | trait_def: &ItemTrait, 566 | proxy_ty_param: &Ident, 567 | ) -> syn::Result { 568 | // A trait with associated consts cannot be implemented for Fn* types. 569 | if proxy_type.is_fn() { 570 | return Err(Error::new( 571 | item.span(), 572 | format_args!("the trait `{}` cannot be auto-implemented for Fn-traits, because it has \ 573 | associated consts (only traits with a single method can be implemented for Fn-traits)", 574 | trait_def.ident) 575 | )); 576 | } 577 | 578 | // We simply use the associated const from our type parameter. 579 | let const_name = &item.ident; 580 | let const_ty = &item.ty; 581 | let attrs = filter_attrs(&item.attrs); 582 | 583 | Ok(quote! { 584 | #(#attrs)* const #const_name: #const_ty = #proxy_ty_param::#const_name; 585 | }) 586 | } 587 | 588 | /// Generates the implementation of an associated type item described by `item`. 589 | /// The implementation is returned as token stream. 590 | /// 591 | /// If the proxy type is an Fn*-trait, an error is emitted and `Err(())` is 592 | /// returned. 593 | fn gen_type_item( 594 | proxy_type: &ProxyType, 595 | item: &TraitItemType, 596 | trait_def: &ItemTrait, 597 | proxy_ty_param: &Ident, 598 | ) -> syn::Result { 599 | // A trait with associated types cannot be implemented for Fn* types. 600 | if proxy_type.is_fn() { 601 | return Err(Error::new( 602 | item.span(), 603 | format_args!("the trait `{}` cannot be auto-implemented for Fn-traits, because it has \ 604 | associated types (only traits with a single method can be implemented for Fn-traits)", 605 | trait_def.ident) 606 | )); 607 | } 608 | 609 | // We simply use the associated type from our type parameter. 610 | let assoc_name = &item.ident; 611 | let attrs = filter_attrs(&item.attrs); 612 | let (impl_generics, type_generics, where_clause) = item.generics.split_for_impl(); 613 | 614 | Ok(quote! { 615 | #(#attrs)* type #assoc_name #impl_generics = #proxy_ty_param::#assoc_name #type_generics #where_clause; 616 | }) 617 | } 618 | 619 | /// Generates the implementation of a method item described by `item`. The 620 | /// implementation is returned as token stream. 621 | /// 622 | /// This function also performs sanity checks, e.g. whether the proxy type can 623 | /// be used to implement the method. If any error occurs, the error is 624 | /// immediately emitted and `Err(())` is returned. 625 | fn gen_method_item( 626 | proxy_type: &ProxyType, 627 | item: &TraitItemFn, 628 | trait_def: &ItemTrait, 629 | proxy_ty_param: &Ident, 630 | ) -> syn::Result { 631 | // If this method has a `#[auto_impl(keep_default_for(...))]` attribute for 632 | // the given proxy type, we don't generate anything for this impl block. 633 | if should_keep_default_for(item, proxy_type)? { 634 | return if item.default.is_some() { 635 | Ok(TokenStream2::new()) 636 | } else { 637 | Err(Error::new( 638 | item.sig.span(), 639 | format_args!( 640 | "the method `{}` has the attribute `keep_default_for` but is not a default \ 641 | method (no body is provided)", 642 | item.sig.ident 643 | ), 644 | )) 645 | }; 646 | } 647 | 648 | // Determine the kind of the method, determined by the self type. 649 | let sig = &item.sig; 650 | let self_arg = SelfType::from_sig(sig); 651 | let attrs = filter_attrs(&item.attrs); 652 | 653 | // Check self type and proxy type combination 654 | check_receiver_compatible(proxy_type, self_arg, &trait_def.ident, sig.span())?; 655 | 656 | // Generate the list of argument used to call the method. 657 | let (inputs, args) = get_arg_list(sig.inputs.iter())?; 658 | 659 | // Construct a signature we'll use to generate the proxy method impl 660 | // This is _almost_ the same as the original, except we use the inputs constructed 661 | // alongside the args. These may be slightly different than the original trait. 662 | let sig = Signature { 663 | constness: item.sig.constness, 664 | asyncness: item.sig.asyncness, 665 | unsafety: item.sig.unsafety, 666 | abi: item.sig.abi.clone(), 667 | fn_token: item.sig.fn_token, 668 | ident: item.sig.ident.clone(), 669 | generics: item.sig.generics.clone(), 670 | paren_token: item.sig.paren_token, 671 | inputs, 672 | variadic: item.sig.variadic.clone(), 673 | output: item.sig.output.clone(), 674 | }; 675 | 676 | // Build the turbofish type parameters. We need to pass type parameters 677 | // explicitly as they cannot be inferred in all cases (e.g. something like 678 | // `mem::size_of`). However, we don't explicitly specify lifetime 679 | // parameters. Most lifetime parameters are so called late-bound lifetimes 680 | // (ones that stick to input parameters) and Rust prohibits us from 681 | // specifying late-bound lifetimes explicitly (which is not a problem, 682 | // because those can always be correctly inferred). It would be possible to 683 | // explicitly specify early-bound lifetimes, but this is hardly useful. 684 | // Early-bound lifetimes are lifetimes that are only attached to the return 685 | // type. Something like: 686 | // 687 | // fn foo<'a>() -> &'a i32 688 | // 689 | // It's hard to imagine how such a function would even work. So since those 690 | // functions are really rare and special, we won't support them. In 691 | // particular, for us to determine if a lifetime parameter is early- or 692 | // late-bound would be *really* difficult. 693 | // 694 | // So we just specify type parameters. In the future, however, we need to 695 | // add support for const parameters. But those are not remotely stable yet, 696 | // so we can wait a bit still. 697 | let generic_types = sig 698 | .generics 699 | .params 700 | .iter() 701 | .filter_map(|param| match param { 702 | GenericParam::Type(param) => { 703 | let name = ¶m.ident; 704 | Some(quote! { #name , }) 705 | } 706 | GenericParam::Const(param) => { 707 | let name = ¶m.ident; 708 | Some(quote! { #name , }) 709 | } 710 | GenericParam::Lifetime(_) => None, 711 | }) 712 | .collect::(); 713 | 714 | let generic_types = if generic_types.is_empty() { 715 | generic_types 716 | } else { 717 | quote! { ::<#generic_types> } 718 | }; 719 | 720 | // Generate the body of the function. This mainly depends on the self type, 721 | // but also on the proxy type. 722 | let fn_name = &sig.ident; 723 | let await_token = sig.asyncness.map(|_| quote! { .await }); 724 | 725 | let body = match self_arg { 726 | // Fn proxy types get a special treatment 727 | _ if proxy_type.is_fn() => { 728 | quote! { ({self})(#args) #await_token } 729 | } 730 | 731 | // No receiver 732 | SelfType::None => { 733 | // The proxy type is a reference, smart pointer or Box. 734 | quote! { #proxy_ty_param::#fn_name #generic_types(#args) #await_token } 735 | } 736 | 737 | // Receiver `self` (by value) 738 | SelfType::Value => { 739 | // The proxy type is a Box. 740 | quote! { #proxy_ty_param::#fn_name #generic_types(*self, #args) #await_token } 741 | } 742 | 743 | // `&self` or `&mut self` receiver 744 | SelfType::Ref | SelfType::Mut => { 745 | // The proxy type could be anything in the `Ref` case, and `&mut` 746 | // or Box in the `Mut` case. 747 | quote! { #proxy_ty_param::#fn_name #generic_types(self, #args) #await_token } 748 | } 749 | }; 750 | 751 | // Combine body with signature 752 | Ok(quote! { #(#attrs)* #sig { #body }}) 753 | } 754 | 755 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 756 | enum SelfType { 757 | None, 758 | Ref, 759 | Mut, 760 | Value, 761 | } 762 | 763 | impl SelfType { 764 | fn from_sig(sig: &Signature) -> Self { 765 | match sig.inputs.iter().next() { 766 | Some(FnArg::Receiver(r)) => { 767 | if r.reference.is_none() { 768 | SelfType::Value 769 | } else if r.mutability.is_none() { 770 | SelfType::Ref 771 | } else { 772 | SelfType::Mut 773 | } 774 | } 775 | _ => SelfType::None, 776 | } 777 | } 778 | 779 | fn as_str(&self) -> Option<&'static str> { 780 | match *self { 781 | SelfType::None => None, 782 | SelfType::Ref => Some("&self"), 783 | SelfType::Mut => Some("&mut self"), 784 | SelfType::Value => Some("self"), 785 | } 786 | } 787 | } 788 | 789 | /// Checks if this method can be implemented for the given proxy type. If not, 790 | /// we will emit an error pointing to the method signature. 791 | fn check_receiver_compatible( 792 | proxy_type: &ProxyType, 793 | self_arg: SelfType, 794 | trait_name: &Ident, 795 | sig_span: Span2, 796 | ) -> syn::Result<()> { 797 | match (proxy_type, self_arg) { 798 | (ProxyType::Ref, SelfType::Mut) | (ProxyType::Ref, SelfType::Value) => { 799 | Err(Error::new( 800 | sig_span, 801 | format_args!("the trait `{}` cannot be auto-implemented for immutable references, because \ 802 | this method has a `{}` receiver (only `&self` and no receiver are allowed)", 803 | trait_name, 804 | self_arg.as_str().unwrap()), 805 | )) 806 | } 807 | 808 | (ProxyType::RefMut, SelfType::Value) => { 809 | Err(Error::new( 810 | sig_span, 811 | format_args!("the trait `{}` cannot be auto-implemented for mutable references, because \ 812 | this method has a `self` receiver (only `&self`, `&mut self` and no receiver are allowed)", 813 | trait_name,) 814 | )) 815 | } 816 | 817 | (ProxyType::Rc, SelfType::Mut) 818 | | (ProxyType::Rc, SelfType::Value) 819 | | (ProxyType::Arc, SelfType::Mut) 820 | | (ProxyType::Arc, SelfType::Value) => { 821 | let ptr_name = if *proxy_type == ProxyType::Rc { 822 | "Rc" 823 | } else { 824 | "Arc" 825 | }; 826 | 827 | Err(Error::new( 828 | sig_span, 829 | format_args!("the trait `{}` cannot be auto-implemented for {}, because \ 830 | this method has a `{}` receiver (only `&self` and no receiver are allowed)", 831 | trait_name, 832 | ptr_name, 833 | self_arg.as_str().unwrap()) 834 | )) 835 | } 836 | 837 | (ProxyType::Fn, _) | (ProxyType::FnMut, _) | (ProxyType::FnOnce, _) => { 838 | // The Fn-trait being compatible with the receiver was already 839 | // checked before (in `gen_fn_type_for_trait()`). 840 | Ok(()) 841 | } 842 | 843 | _ => Ok(()) // All other combinations are fine 844 | } 845 | } 846 | 847 | /// Generates a list of comma-separated arguments used to call the function. 848 | /// Currently, only simple names are valid and more complex pattern will lead 849 | /// to an error being emitted. `self` parameters are ignored. 850 | fn get_arg_list<'a>( 851 | original_inputs: impl Iterator, 852 | ) -> syn::Result<(Punctuated, TokenStream2)> { 853 | let mut args = TokenStream2::new(); 854 | let mut inputs = Punctuated::new(); 855 | 856 | let mut r: Result<(), Error> = Ok(()); 857 | for arg in original_inputs { 858 | match arg { 859 | FnArg::Typed(arg) => { 860 | // Make sure the argument pattern is a simple name. In 861 | // principle, we could probably support patterns, but it's 862 | // not that important now. 863 | if let Pat::Ident(PatIdent { 864 | by_ref: _by_ref, 865 | mutability: _mutability, 866 | ident, 867 | subpat: None, 868 | attrs, 869 | }) = &*arg.pat 870 | { 871 | // Add name plus trailing comma to tokens 872 | args.append_all(quote! { #ident , }); 873 | 874 | // Add an input argument that omits the `mut` and `ref` pattern bindings 875 | inputs.push(FnArg::Typed(PatType { 876 | attrs: arg.attrs.clone(), 877 | pat: Box::new(Pat::Ident(PatIdent { 878 | attrs: attrs.clone(), 879 | by_ref: None, 880 | mutability: None, 881 | ident: ident.clone(), 882 | subpat: None, 883 | })), 884 | colon_token: arg.colon_token, 885 | ty: arg.ty.clone(), 886 | })) 887 | } else { 888 | let err = Error::new( 889 | arg.pat.span(), "argument patterns are not supported by #[auto-impl]; use a simple name like \"foo\" (but not `_`)" 890 | ); 891 | 892 | if let Err(ref mut current_err) = r { 893 | current_err.combine(err); 894 | } else { 895 | r = Err(err); 896 | } 897 | 898 | continue; 899 | } 900 | } 901 | 902 | // There is only one such argument. We handle it elsewhere and 903 | // can ignore it here. 904 | FnArg::Receiver(arg) => { 905 | inputs.push(FnArg::Receiver(arg.clone())); 906 | } 907 | } 908 | } 909 | 910 | r.map(|_| (inputs, args)) 911 | } 912 | 913 | /// Checks if the given method has the attribute `#[auto_impl(keep_default_for(...))]` 914 | /// and if it contains the given proxy type. 915 | fn should_keep_default_for(m: &TraitItemFn, proxy_type: &ProxyType) -> syn::Result { 916 | // Get an iterator of just the attribute we are interested in. 917 | let mut it = m 918 | .attrs 919 | .iter() 920 | .filter(|attr| is_our_attr(attr)) 921 | .map(parse_our_attr); 922 | 923 | // Check the first (and hopefully only) `keep_default_for` attribute. 924 | let out = match it.next() { 925 | Some(attr) => { 926 | // Check if the attribute lists the given proxy type. 927 | let OurAttr::KeepDefaultFor(proxy_types) = attr?; 928 | proxy_types.contains(proxy_type) 929 | } 930 | 931 | // If there is no such attribute, we return `false` 932 | None => false, 933 | }; 934 | 935 | // Check if there is another such attribute (which we disallow) 936 | if it.next().is_some() { 937 | return Err(Error::new( 938 | m.sig.span(), 939 | "found two `keep_default_for` attributes on one method", 940 | )); 941 | } 942 | 943 | Ok(out) 944 | } 945 | 946 | fn filter_attrs(attrs: &[Attribute]) -> Vec { 947 | attrs 948 | .iter() 949 | .filter(|attr| attr.path().is_ident("cfg")) 950 | .cloned() 951 | .collect() 952 | } 953 | -------------------------------------------------------------------------------- /src/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` 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 Trait for &T` | 44 | //! | `&mut` | `impl Trait for &mut T` | 45 | //! | `Box` | `impl Trait for Box` | 46 | //! | `Rc` | `impl Trait for Rc` | 47 | //! | `Arc` | `impl Trait for Arc` | 48 | //! | `Fn` | `impl Trait for T` | 49 | //! | `FnMut` | `impl Trait for T` | 50 | //! | `FnOnce` | `impl 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; 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 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 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 | 206 | extern crate proc_macro; 207 | #[macro_use] 208 | extern crate quote; 209 | 210 | use proc_macro::TokenStream; 211 | 212 | mod analyze; 213 | mod attr; 214 | mod gen; 215 | mod proxy; 216 | 217 | /// See crate documentation for more information. 218 | #[proc_macro_attribute] 219 | pub 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 | 226 | fn auto_impl2( 227 | args: TokenStream, 228 | input: proc_macro2::TokenStream, 229 | ) -> syn::Result { 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::(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 | } 244 | -------------------------------------------------------------------------------- /src/proxy.rs: -------------------------------------------------------------------------------- 1 | use std::iter::Peekable; 2 | use syn::Error; 3 | 4 | use crate::proc_macro::{token_stream, TokenStream, TokenTree}; 5 | 6 | /// Types for which a trait can automatically be implemented. 7 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 8 | pub(crate) enum ProxyType { 9 | Ref, 10 | RefMut, 11 | Arc, 12 | Rc, 13 | Box, 14 | Fn, 15 | FnMut, 16 | FnOnce, 17 | } 18 | 19 | impl ProxyType { 20 | pub(crate) fn is_fn(&self) -> bool { 21 | matches!(*self, ProxyType::Fn | ProxyType::FnMut | ProxyType::FnOnce) 22 | } 23 | } 24 | 25 | /// Parses the attribute token stream into a list of proxy types. 26 | /// 27 | /// The attribute token stream is the one in `#[auto_impl(...)]`. It is 28 | /// supposed to be a comma-separated list of possible proxy types. Legal values 29 | /// are `&`, `&mut`, `Box`, `Rc`, `Arc`, `Fn`, `FnMut` and `FnOnce`. 30 | /// 31 | /// If the given TokenStream is not valid, errors are emitted as appropriate. 32 | /// Erroneous types will not be put into the Vec but rather simply skipped, 33 | /// the emitted errors will abort the compilation anyway. 34 | pub(crate) fn parse_types(args: TokenStream) -> Vec { 35 | let mut out = Vec::new(); 36 | let mut iter = args.into_iter().peekable(); 37 | 38 | // While there are still tokens left... 39 | while iter.peek().is_some() { 40 | // First, we expect one of the proxy types. 41 | if let Ok(ty) = eat_type(&mut iter) { 42 | out.push(ty); 43 | } 44 | 45 | // If the next token is a comma, we eat it (trailing commas are 46 | // allowed). If not, nothing happens (in this case, it's probably the 47 | // end of the stream, otherwise an error will occur later). 48 | let comma_next = 49 | matches!(iter.peek(), Some(TokenTree::Punct(punct)) if punct.as_char() == ','); 50 | 51 | if comma_next { 52 | let _ = iter.next(); 53 | } 54 | } 55 | 56 | out 57 | } 58 | 59 | /// Parses one `ProxyType` from the given token iterator. The iterator must not 60 | /// be empty! 61 | fn eat_type(iter: &mut Peekable) -> syn::Result { 62 | #[rustfmt::skip] 63 | const NOTE_TEXT: &str = "\ 64 | attribute format should be `#[auto_impl()]` where `` is \ 65 | a comma-separated list of types. Allowed values for types: `&`, \ 66 | `&mut`, `Box`, `Rc`, `Arc`, `Fn`, `FnMut` and `FnOnce`.\ 67 | "; 68 | const EXPECTED_TEXT: &str = "expected '&' or ident."; 69 | 70 | // We can unwrap because this function requires the iterator to be 71 | // non-empty. 72 | let ty = match iter.next().unwrap() { 73 | TokenTree::Group(group) => { 74 | return Err(Error::new( 75 | group.span().into(), 76 | format_args!("unexpected group, {}\n{}", EXPECTED_TEXT, NOTE_TEXT), 77 | )); 78 | } 79 | 80 | TokenTree::Literal(lit) => { 81 | return Err(Error::new( 82 | lit.span().into(), 83 | format_args!("unexpected literal, {}\n{}", EXPECTED_TEXT, NOTE_TEXT), 84 | )); 85 | } 86 | 87 | TokenTree::Punct(punct) => { 88 | // Only '&' are allowed. Everything else leads to an error. 89 | if punct.as_char() != '&' { 90 | return Err(Error::new( 91 | punct.span().into(), 92 | format_args!( 93 | "unexpected punctuation '{}', {}\n{}", 94 | punct, EXPECTED_TEXT, NOTE_TEXT 95 | ), 96 | )); 97 | } 98 | 99 | // Check if the next token is `mut`. If not, we will ignore it. 100 | let is_mut_next = 101 | matches!(iter.peek(), Some(TokenTree::Ident(id)) if id.to_string() == "mut"); 102 | 103 | if is_mut_next { 104 | // Eat `mut` 105 | let _ = iter.next(); 106 | ProxyType::RefMut 107 | } else { 108 | ProxyType::Ref 109 | } 110 | } 111 | 112 | TokenTree::Ident(ident) => match &*ident.to_string() { 113 | "Box" => ProxyType::Box, 114 | "Rc" => ProxyType::Rc, 115 | "Arc" => ProxyType::Arc, 116 | "Fn" => ProxyType::Fn, 117 | "FnMut" => ProxyType::FnMut, 118 | "FnOnce" => ProxyType::FnOnce, 119 | _ => { 120 | return Err(Error::new( 121 | ident.span().into(), 122 | format_args!("unexpected '{}', {}\n{}", ident, EXPECTED_TEXT, NOTE_TEXT), 123 | )); 124 | } 125 | }, 126 | }; 127 | 128 | Ok(ty) 129 | } 130 | 131 | // Right now, we can't really write useful tests. Many functions from 132 | // `proc_macro` use a compiler internal session. This session is only valid 133 | // when we were actually called as a proc macro. We need to add tests once 134 | // this limitation of `proc_macro` is fixed. 135 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_enum.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&, &mut)] 5 | enum Foo { 6 | None, 7 | Name(String), 8 | Rgb(u8, u8, u8), 9 | } 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_enum.stderr: -------------------------------------------------------------------------------- 1 | error: expected `trait` 2 | --> tests/compile-fail/attr_on_enum.rs:5:1 3 | | 4 | 5 | enum Foo { 5 | | ^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_fn.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&, &mut)] 5 | fn foo(s: String) -> u32 { 6 | 3 7 | } 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_fn.stderr: -------------------------------------------------------------------------------- 1 | error: expected `trait` 2 | --> tests/compile-fail/attr_on_fn.rs:5:1 3 | | 4 | 5 | fn foo(s: String) -> u32 { 5 | | ^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_impl_block.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | trait Foo {} 5 | 6 | #[auto_impl(&, &mut)] 7 | impl Foo for usize {} 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_impl_block.stderr: -------------------------------------------------------------------------------- 1 | error: expected `trait` 2 | --> tests/compile-fail/attr_on_impl_block.rs:7:1 3 | | 4 | 7 | impl Foo for usize {} 5 | | ^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_struct.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&, &mut)] 5 | struct Foo { 6 | x: usize, 7 | bar: String, 8 | } 9 | 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_struct.stderr: -------------------------------------------------------------------------------- 1 | error: expected `trait` 2 | --> tests/compile-fail/attr_on_struct.rs:5:1 3 | | 4 | 5 | struct Foo { 5 | | ^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_type.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&, &mut)] 5 | type Baz = String; 6 | 7 | 8 | fn main() {} 9 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_type.stderr: -------------------------------------------------------------------------------- 1 | error: expected `trait` 2 | --> tests/compile-fail/attr_on_type.rs:5:1 3 | | 4 | 5 | type Baz = String; 5 | | ^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_unit_struct.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&, &mut)] 5 | struct Foo(usize, String); 6 | 7 | 8 | fn main() {} 9 | -------------------------------------------------------------------------------- /tests/compile-fail/attr_on_unit_struct.stderr: -------------------------------------------------------------------------------- 1 | error: expected `trait` 2 | --> tests/compile-fail/attr_on_unit_struct.rs:5:1 3 | | 4 | 5 | struct Foo(usize, String); 5 | | ^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_associated_const.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait Foo { 6 | const LEN: usize; 7 | 8 | fn a(&self); 9 | } 10 | 11 | 12 | fn main() {} 13 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_associated_const.stderr: -------------------------------------------------------------------------------- 1 | error: this trait cannot be auto-implemented for Fn-traits (only traits with exactly one method and no other items are allowed) 2 | --> tests/compile-fail/fn_associated_const.rs:5:1 3 | | 4 | 5 | / trait Foo { 5 | 6 | | const LEN: usize; 6 | 7 | | 7 | 8 | | fn a(&self); 8 | 9 | | } 9 | | |_^ 10 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_associated_type.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait Foo { 6 | type Out; 7 | 8 | fn a(&self); 9 | } 10 | 11 | 12 | fn main() {} 13 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_associated_type.stderr: -------------------------------------------------------------------------------- 1 | error: this trait cannot be auto-implemented for Fn-traits (only traits with exactly one method and no other items are allowed) 2 | --> tests/compile-fail/fn_associated_type.rs:5:1 3 | | 4 | 5 | / trait Foo { 5 | 6 | | type Out; 6 | 7 | | 7 | 8 | | fn a(&self); 8 | 9 | | } 9 | | |_^ 10 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_const_generics.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait Greeter { 6 | fn greet(&self, id: usize); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_const_generics.stderr: -------------------------------------------------------------------------------- 1 | error: the trait 'Greeter' cannot be implemented for Fn-traits: constant arguments are not allowed 2 | --> tests/compile-fail/fn_const_generics.rs:6:14 3 | | 4 | 6 | fn greet(&self, id: usize); 5 | | ^^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_generics.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | use auto_impl::auto_impl; 3 | 4 | 5 | #[auto_impl(Fn)] 6 | trait Greeter { 7 | fn greet(&self, name: T); 8 | } 9 | 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_generics.stderr: -------------------------------------------------------------------------------- 1 | error: the trait 'Greeter' cannot be implemented for Fn-traits: generic arguments are not allowed 2 | --> tests/compile-fail/fn_generics.rs:7:14 3 | | 4 | 7 | fn greet(&self, name: T); 5 | | ^^^^^^^^^^ 6 | 7 | warning: unused import: `std::fmt::Display` 8 | --> tests/compile-fail/fn_generics.rs:1:5 9 | | 10 | 1 | use std::fmt::Display; 11 | | ^^^^^^^^^^^^^^^^^ 12 | | 13 | = note: `#[warn(unused_imports)]` on by default 14 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_multiple_methods.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait Foo { 6 | fn a(&self); 7 | fn b(&self); 8 | } 9 | 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_multiple_methods.stderr: -------------------------------------------------------------------------------- 1 | error: this trait cannot be auto-implemented for Fn-traits (only traits with exactly one method and no other items are allowed) 2 | --> tests/compile-fail/fn_multiple_methods.rs:5:1 3 | | 4 | 5 | / trait Foo { 5 | 6 | | fn a(&self); 6 | 7 | | fn b(&self); 7 | 8 | | } 8 | | |_^ 9 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_unsafe_method.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait Foo { 6 | unsafe fn a(&self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-fail/fn_unsafe_method.stderr: -------------------------------------------------------------------------------- 1 | error: the trait 'Foo' cannot be auto-implemented for Fn-traits: unsafe methods are not allowed 2 | --> $DIR/fn_unsafe_method.rs:6:5 3 | | 4 | 6 | unsafe fn a(&self); 5 | | ^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/keep_default_for_on_assoc_type.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Foo { 6 | #[auto_impl(keep_default_for(&))] 7 | type Foo; 8 | } 9 | 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-fail/keep_default_for_on_assoc_type.stderr: -------------------------------------------------------------------------------- 1 | error: `#[auto_impl]` attributes are only allowed on methods 2 | --> tests/compile-fail/keep_default_for_on_assoc_type.rs:6:5 3 | | 4 | 6 | / #[auto_impl(keep_default_for(&))] 5 | 7 | | type Foo; 6 | | |_____________^ 7 | -------------------------------------------------------------------------------- /tests/compile-fail/keep_default_for_on_required_method.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Foo { 6 | #[auto_impl(keep_default_for(&))] 7 | fn required(&self); 8 | } 9 | 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-fail/keep_default_for_on_required_method.stderr: -------------------------------------------------------------------------------- 1 | error: the method `required` has the attribute `keep_default_for` but is not a default method (no body is provided) 2 | --> tests/compile-fail/keep_default_for_on_required_method.rs:7:5 3 | | 4 | 7 | fn required(&self); 5 | | ^^^^^^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/method_attr_invalid.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Foo { 6 | #[auto_impl(ferris_for_life)] 7 | fn a(&self); 8 | } 9 | 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-fail/method_attr_invalid.stderr: -------------------------------------------------------------------------------- 1 | error: expected arguments for 'ferris_for_life' in parenthesis `()`, found nothing 2 | --> $DIR/method_attr_invalid.rs:6:17 3 | | 4 | 6 | #[auto_impl(ferris_for_life)] 5 | | ^^^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/mut_self_for_arc.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Arc)] 5 | trait Foo { 6 | fn foo(&mut self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-fail/mut_self_for_arc.stderr: -------------------------------------------------------------------------------- 1 | error: the trait `Foo` cannot be auto-implemented for Arc, because this method has a `&mut self` receiver (only `&self` and no receiver are allowed) 2 | --> tests/compile-fail/mut_self_for_arc.rs:6:5 3 | | 4 | 6 | fn foo(&mut self); 5 | | ^^^^^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/mut_self_for_immutable_ref.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Foo { 6 | fn foo(&mut self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-fail/mut_self_for_immutable_ref.stderr: -------------------------------------------------------------------------------- 1 | error: the trait `Foo` cannot be auto-implemented for immutable references, because this method has a `&mut self` receiver (only `&self` and no receiver are allowed) 2 | --> tests/compile-fail/mut_self_for_immutable_ref.rs:6:5 3 | | 4 | 6 | fn foo(&mut self); 5 | | ^^^^^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/mut_self_for_rc.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Rc)] 5 | trait Foo { 6 | fn foo(&mut self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-fail/mut_self_for_rc.stderr: -------------------------------------------------------------------------------- 1 | error: the trait `Foo` cannot be auto-implemented for Rc, because this method has a `&mut self` receiver (only `&self` and no receiver are allowed) 2 | --> tests/compile-fail/mut_self_for_rc.rs:6:5 3 | | 4 | 6 | fn foo(&mut self); 5 | | ^^^^^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/super_trait_not_implemented.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | trait Supi {} 4 | 5 | #[auto_impl(Box, &)] 6 | trait Foo: Supi {} 7 | 8 | 9 | struct Dog; 10 | impl Supi for Dog {} 11 | impl Foo for Dog {} 12 | 13 | 14 | fn requires_foo(_: T) {} 15 | 16 | fn main() { 17 | requires_foo(Dog); // should work 18 | requires_foo(Box::new(Dog)); // shouldn't, because `Box: Supi` is not satisfied 19 | } 20 | -------------------------------------------------------------------------------- /tests/compile-fail/super_trait_not_implemented.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `Box: Foo` is not satisfied 2 | --> tests/compile-fail/super_trait_not_implemented.rs:18:18 3 | | 4 | 18 | requires_foo(Box::new(Dog)); // shouldn't, because `Box: Supi` is not satisfied 5 | | ------------ ^^^^^^^^^^^^^ the trait `Supi` is not implemented for `Box` 6 | | | 7 | | required by a bound introduced by this call 8 | | 9 | note: required for `Box` to implement `Foo` 10 | --> tests/compile-fail/super_trait_not_implemented.rs:5:1 11 | | 12 | 5 | #[auto_impl(Box, &)] 13 | | ^^^^^^^^^^^^^^^^^^^^ 14 | 6 | trait Foo: Supi {} 15 | | ^^^ ---- unsatisfied trait bound introduced here 16 | note: required by a bound in `requires_foo` 17 | --> tests/compile-fail/super_trait_not_implemented.rs:14:20 18 | | 19 | 14 | fn requires_foo(_: T) {} 20 | | ^^^ required by this bound in `requires_foo` 21 | = note: this error originates in the attribute macro `auto_impl` (in Nightly builds, run with -Z macro-backtrace for more info) 22 | help: consider dereferencing here 23 | | 24 | 18 | requires_foo(*Box::new(Dog)); // shouldn't, because `Box: Supi` is not satisfied 25 | | + 26 | -------------------------------------------------------------------------------- /tests/compile-fail/trait_obj_value_self.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Box)] 5 | trait Trait { 6 | fn foo(self); 7 | } 8 | 9 | fn assert_impl() {} 10 | 11 | fn main() { 12 | assert_impl::>(); 13 | } 14 | -------------------------------------------------------------------------------- /tests/compile-fail/trait_obj_value_self.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time 2 | --> tests/compile-fail/trait_obj_value_self.rs:12:19 3 | | 4 | 12 | assert_impl::>(); 5 | | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time 6 | | 7 | = help: the trait `Sized` is not implemented for `dyn Trait` 8 | = help: the trait `Trait` is implemented for `Box` 9 | note: required for `Box` to implement `Trait` 10 | --> tests/compile-fail/trait_obj_value_self.rs:4:1 11 | | 12 | 4 | #[auto_impl(Box)] 13 | | ^^^^^^^^^^^^^^^^^ 14 | 5 | trait Trait { 15 | | ^^^^^ 16 | note: required by a bound in `assert_impl` 17 | --> tests/compile-fail/trait_obj_value_self.rs:9:19 18 | | 19 | 9 | fn assert_impl() {} 20 | | ^^^^^ required by this bound in `assert_impl` 21 | = note: this error originates in the attribute macro `auto_impl` (in Nightly builds, run with -Z macro-backtrace for more info) 22 | -------------------------------------------------------------------------------- /tests/compile-fail/value_self_for_immutable_ref.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Foo { 6 | fn foo(self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-fail/value_self_for_immutable_ref.stderr: -------------------------------------------------------------------------------- 1 | error: the trait `Foo` cannot be auto-implemented for immutable references, because this method has a `self` receiver (only `&self` and no receiver are allowed) 2 | --> tests/compile-fail/value_self_for_immutable_ref.rs:6:5 3 | | 4 | 6 | fn foo(self); 5 | | ^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-fail/value_self_for_mutable_ref.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&mut)] 5 | trait Foo { 6 | fn foo(self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-fail/value_self_for_mutable_ref.stderr: -------------------------------------------------------------------------------- 1 | error: the trait `Foo` cannot be auto-implemented for mutable references, because this method has a `self` receiver (only `&self`, `&mut self` and no receiver are allowed) 2 | --> tests/compile-fail/value_self_for_mutable_ref.rs:6:5 3 | | 4 | 6 | fn foo(self); 5 | | ^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/compile-pass/associated_type_with_where_clause_for_all_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(Arc, Box, Rc, &, &mut)] 4 | trait HasAssociatedTypeWithBounds { 5 | type AssociatedType<'a, T: From + 'a>; 6 | } 7 | 8 | #[auto_impl(Arc, Box, Rc, &, &mut)] 9 | trait HasAssociatedTypeWithBoundsAndWhereClause { 10 | type AssociatedType<'a, T> 11 | where 12 | T: From + 'a; 13 | } 14 | 15 | #[auto_impl(Arc, Box, Rc, &, &mut)] 16 | trait HasAssociatedTypeWithRedundantBoundsAndWhereClause { 17 | type AssociatedType<'a, T: From + 'a> 18 | where 19 | T: From + 'a; 20 | } 21 | 22 | fn main() {} 23 | -------------------------------------------------------------------------------- /tests/compile-pass/big_trait_for_all_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Arc, Box, Rc, &, &mut)] 5 | trait RefTrait1<'a, T: for<'b> Into<&'b str>> { 6 | type Type1; 7 | type Type2; 8 | 9 | const FOO: u32; 10 | 11 | fn execute1<'b>(&'a self, arg1: &'b T) -> Result; 12 | fn execute2(&self) -> Self::Type2; 13 | } 14 | 15 | 16 | fn main() {} 17 | -------------------------------------------------------------------------------- /tests/compile-pass/big_trait_for_box.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Box)] 5 | trait BoxTrait1<'a, T: for<'b> Into<&'b str>> { 6 | type Type1; 7 | type Type2; 8 | 9 | const FOO: u32; 10 | 11 | fn execute1<'b>(&'a self, arg1: &'b T) -> Result; 12 | fn execute2(&mut self, arg1: i32) -> Self::Type2; 13 | fn execute3(self) -> Self::Type1; 14 | fn execute4(arg1: String) -> Result; 15 | fn execute5() -> String; 16 | } 17 | 18 | 19 | fn main() {} 20 | -------------------------------------------------------------------------------- /tests/compile-pass/big_trait_where_bound_for_all_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Arc, Box, Rc, &, &mut)] 5 | trait Big<'a, T: for<'b> Into<&'b str>> { 6 | type Type1; 7 | type Type2: std::ops::Deref; 8 | 9 | const FOO: u32; 10 | 11 | fn execute1<'b>(&'a self, arg1: &'b T) -> Result 12 | where 13 | T: Clone, 14 | ::Target: Clone; 15 | 16 | fn execute2(&self) -> Self::Type2 17 | where 18 | T: std::ops::Deref; 19 | } 20 | 21 | 22 | fn main() {} 23 | -------------------------------------------------------------------------------- /tests/compile-pass/fn_method_lifetimes.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait FnTrait2<'a, T> { 6 | fn execute<'b, 'c>( 7 | &'a self, 8 | arg1: &'b T, 9 | arg2: &'c T, 10 | arg3: &'static str, 11 | ) -> Result; 12 | } 13 | 14 | 15 | fn main() {} 16 | -------------------------------------------------------------------------------- /tests/compile-pass/generic_fn_method_for_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(&, Arc)] 4 | pub trait OrderStoreFilter { 5 | fn filter(&self, predicate: F) -> Result 6 | where 7 | F: Fn(&str) -> bool; 8 | } 9 | 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-pass/generic_types_and_lifetimes_for_fn.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(Fn)] 4 | trait MyTrait<'a, T> { 5 | fn execute<'b>(&'a self, arg1: &'b T, arg2: &'static str) -> Result<(), String>; 6 | } 7 | 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /tests/compile-pass/generic_types_and_lifetimes_for_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(&, &mut)] 4 | trait MyTrait<'a, T> { 5 | fn execute<'b>(&'a self, arg1: &'b T, arg2: &'static str) -> Result<(), String>; 6 | } 7 | 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /tests/compile-pass/keep_default_for_simple.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Foo { 6 | fn required(&self); 7 | 8 | #[auto_impl(keep_default_for(&))] 9 | fn provided(&self) {} 10 | } 11 | 12 | 13 | fn main() {} 14 | -------------------------------------------------------------------------------- /tests/compile-pass/keep_default_for_with_where_bounds.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Foo { 6 | fn required(&self); 7 | 8 | #[auto_impl(keep_default_for(&))] 9 | fn provided(&self) where Self: Clone {} 10 | } 11 | 12 | 13 | fn main() {} 14 | -------------------------------------------------------------------------------- /tests/compile-pass/method_name_shadowing.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | trait AllExt { 4 | fn foo(&self, _: i32); 5 | } 6 | 7 | impl AllExt for T { 8 | fn foo(&self, _: i32) {} 9 | } 10 | 11 | // This will expand to: 12 | // 13 | // impl Foo for &T { 14 | // fn foo(&self, _x: bool) { 15 | // T::foo(self, _x) 16 | // } 17 | // } 18 | // 19 | // With this test we want to make sure, that the call `T::foo` is always 20 | // unambiguous. Luckily, Rust is nice here. And if we only know `T: Foo`, then 21 | // other global functions are not even considered. Having a test for this 22 | // doesn't hurt though. 23 | #[auto_impl(&)] 24 | trait Foo { 25 | fn foo(&self, _x: bool); 26 | } 27 | 28 | 29 | fn main() {} 30 | -------------------------------------------------------------------------------- /tests/compile-pass/mut_self_for_fn.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait Foo { 6 | fn execute(&mut self); 7 | } 8 | 9 | fn foo(_: impl Foo) {} 10 | 11 | fn bar() { 12 | // Fn 13 | foo(|| {}); 14 | } 15 | 16 | 17 | fn main() {} 18 | -------------------------------------------------------------------------------- /tests/compile-pass/mut_self_for_fn_mut.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(FnMut)] 5 | trait Foo { 6 | fn execute(&mut self); 7 | } 8 | 9 | fn foo(_: impl Foo) {} 10 | 11 | fn bar() { 12 | // FnMut 13 | let mut x = 0; 14 | foo(|| x += 1); 15 | 16 | // Fn 17 | foo(|| {}); 18 | } 19 | 20 | 21 | fn main() {} 22 | -------------------------------------------------------------------------------- /tests/compile-pass/non_inferred_generic_types_for_all_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(&)] 4 | trait Foo { 5 | fn foo(); 6 | fn bar(&self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-pass/non_inferred_generic_types_for_box.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(Box)] 4 | trait Foo { 5 | fn foo(); 6 | fn bar(&self); 7 | fn baz(&mut self); 8 | fn qux(self); 9 | } 10 | 11 | 12 | fn main() {} 13 | -------------------------------------------------------------------------------- /tests/compile-pass/non_inferred_generic_types_with_lifetimes_for_all_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(&)] 4 | trait Foo { 5 | fn foo(); 6 | fn bar(&self); 7 | fn baz<'a, U>() -> &'a str; 8 | fn qux<'a, 'b, 'c, U, V, T>(&self) -> (&'a str, &'b str, &'c str); 9 | } 10 | 11 | 12 | fn main() {} 13 | -------------------------------------------------------------------------------- /tests/compile-pass/ref_self_for_fn.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait Foo { 6 | fn execute(&self); 7 | } 8 | 9 | fn foo(_: impl Foo) {} 10 | 11 | fn bar() { 12 | // Fn 13 | foo(|| {}); 14 | } 15 | 16 | 17 | fn main() {} 18 | -------------------------------------------------------------------------------- /tests/compile-pass/self_bound.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Trait { 6 | fn foo(&self) 7 | where Self: Clone; 8 | } 9 | 10 | #[derive(Clone)] 11 | struct Foo {} 12 | impl Trait for Foo { 13 | fn foo(&self) 14 | where Self: Clone, 15 | {} 16 | } 17 | 18 | fn assert_impl() {} 19 | 20 | fn main() { 21 | assert_impl::(); 22 | assert_impl::<&Foo>(); 23 | } 24 | -------------------------------------------------------------------------------- /tests/compile-pass/self_bound_default_method.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Box)] 5 | trait Trait { 6 | fn bar(&self); 7 | 8 | #[auto_impl(keep_default_for(Box))] 9 | fn foo(&self) 10 | where Self: Clone 11 | {} 12 | } 13 | 14 | fn assert_impl() {} 15 | 16 | struct Foo {} 17 | impl Trait for Foo { 18 | fn bar(&self) {} 19 | } 20 | 21 | fn main() { 22 | assert_impl::(); 23 | assert_impl::>(); 24 | } 25 | -------------------------------------------------------------------------------- /tests/compile-pass/self_bound_multiple.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use auto_impl::auto_impl; 3 | 4 | 5 | #[auto_impl(&)] 6 | trait Trait { 7 | fn foo(&self) 8 | where Self: Clone; 9 | fn bar(&self) 10 | where Self: Default + fmt::Display; 11 | } 12 | 13 | #[derive(Clone, Default)] 14 | struct Foo {} 15 | impl Trait for Foo { 16 | fn foo(&self) 17 | where Self: Clone, 18 | {} 19 | fn bar(&self) 20 | where Self: Default + fmt::Display, 21 | {} 22 | } 23 | 24 | impl fmt::Display for Foo { 25 | fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { 26 | unimplemented!() 27 | } 28 | } 29 | 30 | fn assert_impl() {} 31 | 32 | fn main() { 33 | assert_impl::(); 34 | assert_impl::<&Foo>(); 35 | } 36 | -------------------------------------------------------------------------------- /tests/compile-pass/self_by_value_mut.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | struct Data { 5 | id: usize, 6 | } 7 | 8 | #[auto_impl(&, Box)] 9 | trait Foo { 10 | #[auto_impl(keep_default_for(&))] 11 | fn foo(&self, ref mut data: Data) { 12 | data.id += 1; 13 | } 14 | } 15 | 16 | 17 | fn main() {} 18 | -------------------------------------------------------------------------------- /tests/compile-pass/super_trait_complex_for_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | trait Supi<'a, T> { 4 | fn supi(&self); 5 | } 6 | 7 | #[auto_impl(Box, &)] 8 | trait Foo: Supi<'static, U> 9 | where 10 | Self: Send 11 | { 12 | fn foo(&self) -> i32 { 13 | self.supi(); 14 | 3 15 | } 16 | 17 | fn bar(&self); 18 | } 19 | 20 | 21 | fn main() {} 22 | -------------------------------------------------------------------------------- /tests/compile-pass/super_trait_simple_for_fn_types.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | trait Supi {} 4 | 5 | #[auto_impl(Fn)] 6 | trait Foo: Supi { 7 | fn foo(&self, x: u32) -> String; 8 | } 9 | 10 | 11 | fn main() {} 12 | -------------------------------------------------------------------------------- /tests/compile-pass/super_trait_simple_for_refs.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | trait Supi {} 4 | 5 | #[auto_impl(Box, &)] 6 | trait Foo: Supi {} 7 | 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /tests/compile-pass/trailing_comma.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(&)] 4 | trait MyTrait {} 5 | 6 | fn main() { } 7 | -------------------------------------------------------------------------------- /tests/compile-pass/trait_in_fn.rs: -------------------------------------------------------------------------------- 1 | 2 | fn foo() { 3 | use auto_impl::auto_impl; 4 | 5 | #[auto_impl(Fn)] 6 | trait Foo<'a, T> { 7 | fn execute<'b>( 8 | &'a self, 9 | arg1: &'b T, 10 | arg3: &'static str, 11 | ) -> Result; 12 | } 13 | 14 | #[auto_impl(&, &mut, Box, Rc, Arc)] 15 | trait Bar<'a, T> { 16 | fn execute<'b>( 17 | &'a self, 18 | arg1: &'b T, 19 | arg3: &'static str, 20 | ) -> Result; 21 | } 22 | 23 | println!("yooo"); 24 | } 25 | 26 | 27 | fn main() {} 28 | -------------------------------------------------------------------------------- /tests/compile-pass/trait_in_mods.rs: -------------------------------------------------------------------------------- 1 | // Make sure that everything compiles even without the prelude. This basically 2 | // forces us to generate full paths for types of the standard/core library. 3 | // 4 | // Note that `no_implicit_prelude` attribute appears to interact strangely 5 | // with Rust's 2018 style modules and extern crates. 6 | #![no_implicit_prelude] 7 | 8 | extern crate std; 9 | extern crate auto_impl; 10 | 11 | 12 | mod outer { 13 | use crate::{ 14 | auto_impl::auto_impl, 15 | std::{ 16 | string::String, 17 | result::Result, 18 | } 19 | }; 20 | 21 | #[auto_impl(Fn)] 22 | trait Foo<'a, T> { 23 | fn execute<'b>( 24 | &'a self, 25 | arg1: &'b T, 26 | arg3: &'static str, 27 | ) -> Result; 28 | } 29 | 30 | #[auto_impl(&, &mut, Box, Rc, Arc)] 31 | trait Bar<'a, T> { 32 | fn execute<'b>( 33 | &'a self, 34 | arg1: &'b T, 35 | arg3: &'static str, 36 | ) -> Result; 37 | } 38 | 39 | mod inner { 40 | use crate::{ 41 | auto_impl::auto_impl, 42 | std::{ 43 | string::String, 44 | result::Result, 45 | } 46 | }; 47 | 48 | #[auto_impl(Fn)] 49 | trait Foo<'a, T> { 50 | fn execute<'b>( 51 | &'a self, 52 | arg1: &'b T, 53 | arg3: &'static str, 54 | ) -> Result; 55 | } 56 | 57 | #[auto_impl(&, &mut, Box, Rc, Arc)] 58 | trait Bar<'a, T> { 59 | fn execute<'b>( 60 | &'a self, 61 | arg1: &'b T, 62 | arg3: &'static str, 63 | ) -> Result; 64 | } 65 | } 66 | } 67 | 68 | 69 | fn main() {} 70 | -------------------------------------------------------------------------------- /tests/compile-pass/trait_obj_default_method.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Box)] 5 | trait Trait { 6 | fn bar(&self); 7 | 8 | #[auto_impl(keep_default_for(Box))] 9 | fn foo(self) where Self: Sized {} 10 | } 11 | 12 | fn assert_impl() {} 13 | 14 | struct Foo {} 15 | impl Trait for Foo { 16 | fn bar(&self) {} 17 | } 18 | 19 | fn main() { 20 | assert_impl::(); 21 | assert_impl::>(); 22 | } 23 | -------------------------------------------------------------------------------- /tests/compile-pass/trait_obj_immutable_self.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&, &mut, Box, Rc, Arc)] 5 | trait Trait { 6 | fn foo(&self); 7 | } 8 | 9 | fn assert_impl() {} 10 | 11 | fn main() { 12 | use std::{rc::Rc, sync::Arc}; 13 | 14 | assert_impl::<&dyn Trait>(); 15 | assert_impl::<&mut dyn Trait>(); 16 | assert_impl::>(); 17 | assert_impl::>(); 18 | assert_impl::>(); 19 | } 20 | -------------------------------------------------------------------------------- /tests/compile-pass/trait_obj_self_sized.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Box)] 5 | trait Foo: Sized { 6 | fn foo(&self); 7 | } 8 | 9 | #[auto_impl(Box)] 10 | trait Bar where Self: Sized { 11 | fn foo(&self); 12 | } 13 | 14 | #[auto_impl(Box)] 15 | trait Baz: Sized where Self: Sized { 16 | fn foo(&self); 17 | } 18 | 19 | 20 | fn main() {} 21 | -------------------------------------------------------------------------------- /tests/compile-pass/trait_obj_value_self.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Box)] 5 | trait Trait { 6 | fn foo(self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/compile-pass/value_self_for_fn.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(Fn)] 5 | trait Foo { 6 | fn execute(self); 7 | } 8 | 9 | fn foo(_: impl Foo) {} 10 | 11 | fn bar() { 12 | // Fn 13 | foo(|| {}); 14 | } 15 | 16 | 17 | fn main() {} 18 | -------------------------------------------------------------------------------- /tests/compile-pass/value_self_for_fn_mut.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(FnMut)] 5 | trait Foo { 6 | fn execute(self); 7 | } 8 | 9 | fn foo(_: impl Foo) {} 10 | 11 | fn bar() { 12 | // FnMut 13 | let mut x = 0; 14 | foo(|| x += 1); 15 | 16 | // Fn 17 | foo(|| {}); 18 | } 19 | 20 | 21 | fn main() {} 22 | -------------------------------------------------------------------------------- /tests/compile-pass/value_self_for_fn_once.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(FnOnce)] 5 | trait Foo { 6 | fn execute(self); 7 | } 8 | 9 | fn foo(_: impl Foo) {} 10 | 11 | fn bar() { 12 | // FnOnce 13 | let s = String::new(); 14 | foo(|| drop(s)); 15 | 16 | // FnMut 17 | let mut x = 0; 18 | foo(|| x += 1); 19 | 20 | // Fn 21 | foo(|| {}); 22 | } 23 | 24 | 25 | fn main() {} 26 | -------------------------------------------------------------------------------- /tests/no_std.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(dead_code)] 3 | 4 | use auto_impl::auto_impl; 5 | 6 | mod core {} 7 | 8 | mod alloc {} 9 | 10 | struct Box; 11 | struct Rc; 12 | struct Arc; 13 | struct Fn; 14 | struct FnMut; 15 | 16 | #[auto_impl(&, &mut, Box, Rc, Arc)] 17 | trait Test {} 18 | 19 | #[auto_impl(Fn)] 20 | trait TestFn { 21 | fn test(&self); 22 | } 23 | 24 | #[auto_impl(FnMut)] 25 | trait TestFnMut { 26 | fn test(&mut self); 27 | } 28 | -------------------------------------------------------------------------------- /tests/since_1.51/compile-pass/associated_lifetime.rs: -------------------------------------------------------------------------------- 1 | #[auto_impl::auto_impl(&, Arc, Box)] 2 | pub trait Trait { 3 | type Type<'a, T>: Iterator + 'a; 4 | } 5 | 6 | fn main() {} -------------------------------------------------------------------------------- /tests/since_1.51/compile-pass/generic_const_method.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | 4 | #[auto_impl(&)] 5 | trait Foo { 6 | fn foo(&self); 7 | } 8 | 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /tests/since_1.51/compile-pass/generic_mix.rs: -------------------------------------------------------------------------------- 1 | use auto_impl::auto_impl; 2 | 3 | #[auto_impl(&, &mut)] 4 | trait MyTrait<'a, T> { 5 | fn execute<'b, U, const N: usize>(&'a self, arg1: &'b T, arg2: &'static str, arg3: U) -> Result<(), String>; 6 | } 7 | 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /tests/since_1.75/compile-pass/async_trait.rs: -------------------------------------------------------------------------------- 1 | #[auto_impl::auto_impl(&, &mut, Arc, Box, Rc)] 2 | trait AsyncTrait { 3 | async fn foo(&self); 4 | } 5 | 6 | fn main() {} 7 | -------------------------------------------------------------------------------- /tests/ui.rs: -------------------------------------------------------------------------------- 1 | use trybuild::TestCases; 2 | 3 | #[test] 4 | fn ui_compile_pass() { 5 | let t = TestCases::new(); 6 | t.pass("tests/compile-pass/*.rs"); 7 | } 8 | 9 | #[rustversion::nightly] 10 | #[test] 11 | fn ui_compile_fail() { 12 | let t = TestCases::new(); 13 | t.compile_fail("tests/compile-fail/*.rs"); 14 | } 15 | 16 | #[rustversion::since(1.51)] 17 | #[test] 18 | fn ui_since_1_51_compile_pass() { 19 | let t = TestCases::new(); 20 | t.pass("tests/since_1.51/compile-pass/*.rs"); 21 | } 22 | 23 | #[rustversion::since(1.75)] 24 | #[test] 25 | fn ui_since_1_75_compile_pass() { 26 | let t = TestCases::new(); 27 | t.pass("tests/since_1.75/compile-pass/*.rs"); 28 | } 29 | --------------------------------------------------------------------------------