├── .github └── workflows │ └── rust.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── rust-toolchain.toml ├── trait-transformer ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── examples │ └── trait_transformer.rs └── src │ ├── lib.rs │ └── transformer.rs └── trait-variant ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── examples └── variant.rs └── src ├── lib.rs └── variant.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: cargo build --locked --verbose 21 | - name: Run tests 22 | run: cargo test --locked --verbose 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of 9 | experience, education, socio-economic status, nationality, personal appearance, 10 | race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or reject 41 | comments, commits, code, wiki edits, issues, and other contributions that are 42 | not aligned to this Code of Conduct, or to ban temporarily or permanently any 43 | contributor for other behaviors that they deem inappropriate, threatening, 44 | offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | This Code of Conduct also applies outside the project spaces when the Project 56 | Steward has a reasonable belief that an individual's behavior may have a 57 | negative impact on the project or its community. 58 | 59 | ## Conflict Resolution 60 | 61 | We do not believe that all conflict is bad; healthy debate and disagreement 62 | often yield positive results. However, it is never okay to be disrespectful or 63 | to engage in behavior that violates the project’s code of conduct. 64 | 65 | If you see someone violating the code of conduct, you are encouraged to address 66 | the behavior directly with those involved. Many issues can be resolved quickly 67 | and easily, and this gives people more control over the outcome of their 68 | dispute. If you are unable to resolve the matter for any reason, or if the 69 | behavior is threatening or harassing, report it. We are dedicated to providing 70 | an environment where participants feel welcome and safe. 71 | 72 | Reports should be directed to David Koloski , the 73 | Project Steward(s) for `impl_trait_utils`. It is the Project Steward’s duty to 74 | receive and address reported violations of the code of conduct. They will then 75 | work with a committee consisting of representatives from the Open Source 76 | Programs Office and the Google Open Source Strategy team. If for any reason you 77 | are uncomfortable reaching out to the Project Steward, please email 78 | opensource@google.com. 79 | 80 | We will investigate every complaint, but you may not receive a direct response. 81 | We will use our discretion in determining when and how to follow up on reported 82 | incidents, which may range from not taking action to permanent expulsion from 83 | the project and project-sponsored spaces. We will notify the accused of the 84 | report and provide them an opportunity to discuss it before any action is taken. 85 | The identity of the reporter will be omitted from the details of the report 86 | supplied to the accused. In potentially harmful situations, such as ongoing 87 | harassment or threats to anyone's safety, we may take action without notice. 88 | 89 | ## Attribution 90 | 91 | This Code of Conduct is adapted from the Contributor Covenant, version 1.4, 92 | available at 93 | https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 94 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We'd love to accept your patches and contributions to this project. 4 | 5 | ## Before you begin 6 | 7 | ### Sign our Contributor License Agreement 8 | 9 | Contributions to this project must be accompanied by a 10 | [Contributor License Agreement](https://cla.developers.google.com/about) (CLA). 11 | You (or your employer) retain the copyright to your contribution; this simply 12 | gives us permission to use and redistribute your contributions as part of the 13 | project. 14 | 15 | If you or your current employer have already signed the Google CLA (even if it 16 | was for a different project), you probably don't need to do it again. 17 | 18 | Visit to see your current agreements or to 19 | sign a new one. 20 | 21 | ### Review our community guidelines 22 | 23 | This project follows 24 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 25 | 26 | ## Contribution process 27 | 28 | ### Code reviews 29 | 30 | All submissions, including submissions by project members, require review. We 31 | use GitHub pull requests for this purpose. Consult 32 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 33 | information on using pull requests. 34 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "backtrace" 22 | version = "0.3.69" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" 25 | dependencies = [ 26 | "addr2line", 27 | "cc", 28 | "cfg-if", 29 | "libc", 30 | "miniz_oxide", 31 | "object", 32 | "rustc-demangle", 33 | ] 34 | 35 | [[package]] 36 | name = "cc" 37 | version = "1.0.83" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 40 | dependencies = [ 41 | "libc", 42 | ] 43 | 44 | [[package]] 45 | name = "cfg-if" 46 | version = "1.0.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 49 | 50 | [[package]] 51 | name = "gimli" 52 | version = "0.28.1" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 55 | 56 | [[package]] 57 | name = "libc" 58 | version = "0.2.150" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" 61 | 62 | [[package]] 63 | name = "memchr" 64 | version = "2.6.4" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" 67 | 68 | [[package]] 69 | name = "miniz_oxide" 70 | version = "0.7.1" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 73 | dependencies = [ 74 | "adler", 75 | ] 76 | 77 | [[package]] 78 | name = "object" 79 | version = "0.32.1" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" 82 | dependencies = [ 83 | "memchr", 84 | ] 85 | 86 | [[package]] 87 | name = "pin-project-lite" 88 | version = "0.2.13" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 91 | 92 | [[package]] 93 | name = "proc-macro2" 94 | version = "1.0.70" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" 97 | dependencies = [ 98 | "unicode-ident", 99 | ] 100 | 101 | [[package]] 102 | name = "quote" 103 | version = "1.0.33" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 106 | dependencies = [ 107 | "proc-macro2", 108 | ] 109 | 110 | [[package]] 111 | name = "rustc-demangle" 112 | version = "0.1.23" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 115 | 116 | [[package]] 117 | name = "syn" 118 | version = "2.0.39" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" 121 | dependencies = [ 122 | "proc-macro2", 123 | "quote", 124 | "unicode-ident", 125 | ] 126 | 127 | [[package]] 128 | name = "tokio" 129 | version = "1.35.0" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" 132 | dependencies = [ 133 | "backtrace", 134 | "pin-project-lite", 135 | ] 136 | 137 | [[package]] 138 | name = "trait-transformer" 139 | version = "0.0.0" 140 | dependencies = [ 141 | "proc-macro2", 142 | "quote", 143 | "syn", 144 | "tokio", 145 | ] 146 | 147 | [[package]] 148 | name = "trait-variant" 149 | version = "0.1.2" 150 | dependencies = [ 151 | "proc-macro2", 152 | "quote", 153 | "syn", 154 | "tokio", 155 | ] 156 | 157 | [[package]] 158 | name = "unicode-ident" 159 | version = "1.0.12" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 162 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "trait-variant", 4 | "trait-transformer", 5 | ] 6 | 7 | resolver = "2" 8 | 9 | [workspace.package] 10 | repository = "https://github.com/rust-lang/impl-trait-utils" 11 | license = "MIT OR Apache-2.0" 12 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Latest Version]][crates.io] [![Documentation]][docs.rs] [![GHA Status]][GitHub Actions] ![License] 2 | 3 | Utilities for working with `impl Trait`s in Rust. 4 | 5 | ## `trait_variant` 6 | 7 | `trait_variant` generates a specialized version of a base trait that uses `async fn` and/or `-> impl Trait`. 8 | 9 | For example, if you want a [`Send`][rust-std-send]able version of your trait, you'd write: 10 | 11 | ```rust 12 | #[trait_variant::make(IntFactory: Send)] 13 | trait LocalIntFactory { 14 | async fn make(&self) -> i32; 15 | fn stream(&self) -> impl Iterator; 16 | fn call(&self) -> u32; 17 | } 18 | ``` 19 | 20 | The `trait_variant::make` would generate an additional trait called `IntFactory`: 21 | 22 | ```rust 23 | use core::future::Future; 24 | 25 | trait IntFactory: Send { 26 | fn make(&self) -> impl Future + Send; 27 | fn stream(&self) -> impl Iterator + Send; 28 | fn call(&self) -> u32; 29 | } 30 | ``` 31 | 32 | Implementers can choose to implement either `LocalIntFactory` or `IntFactory` as appropriate. 33 | 34 | For more details, see the docs for [`trait_variant::make`]. 35 | 36 | [`trait_variant::make`]: https://docs.rs/trait-variant/latest/trait_variant/attr.make.html 37 | 38 | #### License and usage notes 39 | 40 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or 41 | [MIT license](LICENSE-MIT) at your option. 42 | 43 | [GitHub Actions]: https://github.com/rust-lang/impl-trait-utils/actions 44 | [GHA Status]: https://github.com/rust-lang/impl-trait-utils/actions/workflows/rust.yml/badge.svg 45 | [crates.io]: https://crates.io/crates/trait-variant 46 | [Latest Version]: https://img.shields.io/crates/v/trait-variant.svg 47 | [Documentation]: https://img.shields.io/docsrs/trait-variant 48 | [docs.rs]: https://docs.rs/trait-variant 49 | [License]: https://img.shields.io/crates/l/trait-variant.svg 50 | [rust-std-send]: https://doc.rust-lang.org/std/marker/trait.Send.html 51 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /trait-transformer/Cargo.toml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 or the MIT license 5 | # , at your 6 | # option. This file may not be copied, modified, or distributed 7 | # except according to those terms. 8 | 9 | [package] 10 | name = "trait-transformer" 11 | version = "0.0.0" 12 | description = "Utilities for working with impl traits in Rust" 13 | categories = ["asynchronous", "no-std", "rust-patterns"] 14 | keywords = ["async", "trait", "impl"] 15 | license.workspace = true 16 | repository.workspace = true 17 | edition = "2021" 18 | 19 | [lib] 20 | proc-macro = true 21 | 22 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 23 | 24 | [dependencies] 25 | proc-macro2 = "1.0" 26 | quote = "1.0" 27 | syn = { version = "2.0", features = ["full"] } 28 | 29 | [dev-dependencies] 30 | tokio = { version = "1", features = ["rt"] } 31 | -------------------------------------------------------------------------------- /trait-transformer/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../LICENSE-APACHE -------------------------------------------------------------------------------- /trait-transformer/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../LICENSE-MIT -------------------------------------------------------------------------------- /trait-transformer/README.md: -------------------------------------------------------------------------------- 1 | ## `trait_transformer` 2 | 3 | `trait_transformer` does the same thing as `trait_variant`, but using experimental nightly-only syntax that depends on the `return_type_notation` feature. It may be used to experiment with new kinds of trait transformations in the future. 4 | -------------------------------------------------------------------------------- /trait-transformer/examples/trait_transformer.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![allow(incomplete_features)] 10 | #![feature(return_type_notation)] 11 | 12 | use std::iter; 13 | 14 | use trait_transformer::trait_transformer; 15 | 16 | #[trait_transformer(SendIntFactory: Send)] 17 | trait IntFactory { 18 | async fn make(&self) -> i32; 19 | // ..or.. 20 | fn stream(&self) -> impl Iterator; 21 | fn call(&self) -> u32; 22 | } 23 | 24 | fn thing(factory: impl SendIntFactory + 'static) { 25 | tokio::task::spawn(async move { 26 | factory.make().await; 27 | }); 28 | } 29 | 30 | struct MyFactory; 31 | 32 | impl IntFactory for MyFactory { 33 | async fn make(&self) -> i32 { 34 | todo!() 35 | } 36 | 37 | fn stream(&self) -> impl Iterator { 38 | iter::empty() 39 | } 40 | 41 | fn call(&self) -> u32 { 42 | 0 43 | } 44 | } 45 | impl SendIntFactory for MyFactory {} 46 | 47 | fn main() { 48 | let my_factory = MyFactory; 49 | thing(my_factory); 50 | } 51 | -------------------------------------------------------------------------------- /trait-transformer/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | mod transformer; 10 | 11 | #[proc_macro_attribute] 12 | pub fn trait_transformer( 13 | attr: proc_macro::TokenStream, 14 | item: proc_macro::TokenStream, 15 | ) -> proc_macro::TokenStream { 16 | transformer::trait_transformer(attr, item) 17 | } 18 | -------------------------------------------------------------------------------- /trait-transformer/src/transformer.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use proc_macro2::TokenStream; 10 | use quote::quote; 11 | use syn::{ 12 | parse::{Parse, ParseStream}, 13 | parse_macro_input, 14 | punctuated::Punctuated, 15 | token::Comma, 16 | Ident, ItemTrait, Path, Result, ReturnType, Token, TraitBound, TraitBoundModifier, TraitItem, 17 | Type, 18 | }; 19 | 20 | struct Attrs { 21 | traits: Punctuated, 22 | } 23 | 24 | impl Parse for Attrs { 25 | fn parse(input: ParseStream) -> Result { 26 | Ok(Self { 27 | traits: input.parse_terminated(Transform::parse, Token![,])?, 28 | }) 29 | } 30 | } 31 | 32 | struct Transform { 33 | subtrait_name: Ident, 34 | #[allow(dead_code)] 35 | colon: Token![:], 36 | subtrait: Path, 37 | } 38 | 39 | impl Parse for Transform { 40 | fn parse(input: ParseStream) -> Result { 41 | Ok(Self { 42 | subtrait_name: input.parse()?, 43 | colon: input.parse()?, 44 | subtrait: input.parse()?, 45 | }) 46 | } 47 | } 48 | 49 | pub fn trait_transformer( 50 | attr: proc_macro::TokenStream, 51 | item: proc_macro::TokenStream, 52 | ) -> proc_macro::TokenStream { 53 | let attrs = parse_macro_input!(attr as Attrs); 54 | let item = parse_macro_input!(item as ItemTrait); 55 | 56 | let transformed_trait = transform_trait(&attrs, &item); 57 | let output = quote! { 58 | #item 59 | #transformed_trait 60 | }; 61 | 62 | output.into() 63 | } 64 | 65 | fn transform_trait(attrs: &Attrs, tr: &ItemTrait) -> TokenStream { 66 | let traits = attrs 67 | .traits 68 | .iter() 69 | .map(|attr| { 70 | let subtrait = &attr.subtrait; 71 | let fn_bounds = tr.items.iter().filter_map(|item| { 72 | match item { 73 | TraitItem::Fn(item_fn) => { 74 | let is_async = item_fn.sig.asyncness.is_some(); 75 | let returns_impl_trait = 76 | if let ReturnType::Type(_, ty) = &item_fn.sig.output { 77 | matches!(**ty, Type::ImplTrait(_)) 78 | } else { 79 | false 80 | }; 81 | 82 | if is_async || returns_impl_trait { 83 | let name = &item_fn.sig.ident; 84 | return Some(quote! { #name(): #subtrait }); 85 | } 86 | } 87 | _ => (), 88 | } 89 | None 90 | }); 91 | 92 | let tr_ident = &tr.ident; 93 | let supertrait = syn::TypeParamBound::Verbatim(quote! { 94 | #tr_ident<#(#fn_bounds),*> 95 | }); 96 | 97 | ItemTrait { 98 | attrs: Vec::new(), 99 | ident: attr.subtrait_name.clone(), 100 | items: Vec::new(), 101 | supertraits: Punctuated::from_iter( 102 | vec![ 103 | supertrait, 104 | syn::TypeParamBound::Trait(TraitBound { 105 | paren_token: None, 106 | modifier: TraitBoundModifier::None, 107 | lifetimes: None, 108 | path: attr.subtrait.clone(), 109 | }), 110 | ] 111 | .into_iter(), 112 | ), 113 | ..tr.clone() 114 | } 115 | }) 116 | .collect::>(); 117 | 118 | quote! { #(#traits)* } 119 | } 120 | -------------------------------------------------------------------------------- /trait-variant/Cargo.toml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 or the MIT license 5 | # , at your 6 | # option. This file may not be copied, modified, or distributed 7 | # except according to those terms. 8 | 9 | [package] 10 | name = "trait-variant" 11 | version = "0.1.2" 12 | description = "Utilities for working with impl traits in Rust" 13 | categories = ["asynchronous", "no-std", "rust-patterns"] 14 | keywords = ["async", "trait", "impl"] 15 | license.workspace = true 16 | repository.workspace = true 17 | edition = "2021" 18 | rust-version = "1.75" 19 | 20 | [lib] 21 | proc-macro = true 22 | 23 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 24 | 25 | [dependencies] 26 | proc-macro2 = "1.0" 27 | quote = "1.0" 28 | syn = { version = "2.0", features = ["full"] } 29 | 30 | [dev-dependencies] 31 | tokio = { version = "1", features = ["rt"] } 32 | -------------------------------------------------------------------------------- /trait-variant/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../LICENSE-APACHE -------------------------------------------------------------------------------- /trait-variant/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../LICENSE-MIT -------------------------------------------------------------------------------- /trait-variant/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /trait-variant/examples/variant.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use std::{fmt::Display, future::Future}; 10 | 11 | #[trait_variant::make(IntFactory: Send)] 12 | pub trait LocalIntFactory { 13 | const NAME: &'static str; 14 | 15 | type MyFut<'a>: Future 16 | where 17 | Self: 'a; 18 | 19 | async fn make(&self, x: u32, y: &str) -> i32; 20 | fn stream(&self) -> impl Iterator; 21 | fn call(&self) -> u32; 22 | fn another_async(&self, input: Result<(), &str>) -> Self::MyFut<'_>; 23 | } 24 | 25 | #[allow(dead_code)] 26 | fn spawn_task(factory: impl IntFactory + 'static) { 27 | tokio::spawn(async move { 28 | let _int = factory.make(1, "foo").await; 29 | }); 30 | } 31 | 32 | #[trait_variant::make(GenericTrait: Send)] 33 | pub trait LocalGenericTrait<'x, S: Sync, Y, const X: usize> 34 | where 35 | Y: Sync, 36 | { 37 | const CONST: usize = 3; 38 | type F; 39 | type A; 40 | type B: FromIterator; 41 | 42 | async fn take(&self, s: S); 43 | fn build(&self, items: impl Iterator) -> Self::B; 44 | } 45 | 46 | #[trait_variant::make(Send + Sync)] 47 | pub trait GenericTraitWithBounds<'x, S: Sync, Y, const X: usize> 48 | where 49 | Y: Sync, 50 | { 51 | const CONST: usize = 3; 52 | type F; 53 | type A; 54 | type B: FromIterator; 55 | 56 | async fn take(&self, s: S); 57 | fn build(&self, items: impl Iterator) -> Self::B; 58 | } 59 | 60 | fn main() {} 61 | -------------------------------------------------------------------------------- /trait-variant/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | #![doc = include_str!("../README.md")] 10 | 11 | mod variant; 12 | 13 | /// Creates a specialized version of a base trait that adds bounds to `async 14 | /// fn` and/or `-> impl Trait` return types. 15 | /// 16 | /// ``` 17 | /// #[trait_variant::make(Send)] 18 | /// trait IntFactory { 19 | /// async fn make(&self) -> i32; 20 | /// fn stream(&self) -> impl Iterator; 21 | /// fn call(&self) -> u32; 22 | /// } 23 | /// ``` 24 | /// 25 | /// The above example causes the trait to be rewritten as: 26 | /// 27 | /// ``` 28 | /// # use core::future::Future; 29 | /// trait IntFactory: Send { 30 | /// fn make(&self) -> impl Future + Send; 31 | /// fn stream(&self) -> impl Iterator + Send; 32 | /// fn call(&self) -> u32; 33 | /// } 34 | /// ``` 35 | /// 36 | /// Note that ordinary methods such as `call` are not affected. 37 | /// 38 | /// If you want to preserve an original trait untouched, `make` can be used to create a new trait with bounds on `async 39 | /// fn` and/or `-> impl Trait` return types. 40 | /// 41 | /// ``` 42 | /// #[trait_variant::make(IntFactory: Send)] 43 | /// trait LocalIntFactory { 44 | /// async fn make(&self) -> i32; 45 | /// fn stream(&self) -> impl Iterator; 46 | /// fn call(&self) -> u32; 47 | /// } 48 | /// ``` 49 | /// 50 | /// The example causes a second trait called `IntFactory` to be created. 51 | /// Implementers of the trait can choose to implement the variant instead of the 52 | /// original trait. The macro creates a blanket impl which ensures that any type 53 | /// which implements the variant also implements the original trait. 54 | #[proc_macro_attribute] 55 | pub fn make( 56 | attr: proc_macro::TokenStream, 57 | item: proc_macro::TokenStream, 58 | ) -> proc_macro::TokenStream { 59 | variant::make(attr, item) 60 | } 61 | -------------------------------------------------------------------------------- /trait-variant/src/variant.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | use std::iter; 10 | 11 | use proc_macro2::TokenStream; 12 | use quote::quote; 13 | use syn::{ 14 | parse::{Parse, ParseStream}, 15 | parse_macro_input, parse_quote, 16 | punctuated::Punctuated, 17 | token::Plus, 18 | Error, FnArg, GenericParam, Ident, ItemTrait, Pat, PatType, Result, ReturnType, Signature, 19 | Token, TraitBound, TraitItem, TraitItemConst, TraitItemFn, TraitItemType, Type, TypeGenerics, 20 | TypeImplTrait, TypeParam, TypeParamBound, 21 | }; 22 | 23 | struct Attrs { 24 | variant: MakeVariant, 25 | } 26 | 27 | impl Parse for Attrs { 28 | fn parse(input: ParseStream) -> Result { 29 | Ok(Self { 30 | variant: MakeVariant::parse(input)?, 31 | }) 32 | } 33 | } 34 | 35 | enum MakeVariant { 36 | // Creates a variant of a trait under a new name with additional bounds while preserving the original trait. 37 | Create { 38 | name: Ident, 39 | _colon: Token![:], 40 | bounds: Punctuated, 41 | }, 42 | // Rewrites the original trait into a new trait with additional bounds. 43 | Rewrite { 44 | bounds: Punctuated, 45 | }, 46 | } 47 | 48 | impl Parse for MakeVariant { 49 | fn parse(input: ParseStream) -> Result { 50 | let variant = if input.peek(Ident) && input.peek2(Token![:]) { 51 | MakeVariant::Create { 52 | name: input.parse()?, 53 | _colon: input.parse()?, 54 | bounds: input.parse_terminated(TraitBound::parse, Token![+])?, 55 | } 56 | } else { 57 | MakeVariant::Rewrite { 58 | bounds: input.parse_terminated(TraitBound::parse, Token![+])?, 59 | } 60 | }; 61 | Ok(variant) 62 | } 63 | } 64 | 65 | pub fn make( 66 | attr: proc_macro::TokenStream, 67 | item: proc_macro::TokenStream, 68 | ) -> proc_macro::TokenStream { 69 | let attrs = parse_macro_input!(attr as Attrs); 70 | let item = parse_macro_input!(item as ItemTrait); 71 | 72 | match attrs.variant { 73 | MakeVariant::Create { name, bounds, .. } => { 74 | let maybe_allow_async_lint = if bounds 75 | .iter() 76 | .any(|b| b.path.segments.last().unwrap().ident == "Send") 77 | { 78 | quote! { #[allow(async_fn_in_trait)] } 79 | } else { 80 | quote! {} 81 | }; 82 | 83 | let variant = mk_variant(&name, bounds, &item); 84 | let blanket_impl = mk_blanket_impl(&name, &item); 85 | 86 | quote! { 87 | #maybe_allow_async_lint 88 | #item 89 | 90 | #variant 91 | 92 | #blanket_impl 93 | } 94 | .into() 95 | } 96 | MakeVariant::Rewrite { bounds, .. } => { 97 | let variant = mk_variant(&item.ident, bounds, &item); 98 | quote! { 99 | #variant 100 | } 101 | .into() 102 | } 103 | } 104 | } 105 | 106 | fn mk_variant( 107 | variant: &Ident, 108 | with_bounds: Punctuated, 109 | tr: &ItemTrait, 110 | ) -> TokenStream { 111 | let bounds: Vec<_> = with_bounds 112 | .into_iter() 113 | .map(|b| TypeParamBound::Trait(b.clone())) 114 | .collect(); 115 | let variant = ItemTrait { 116 | ident: variant.clone(), 117 | supertraits: tr.supertraits.iter().chain(&bounds).cloned().collect(), 118 | items: tr 119 | .items 120 | .iter() 121 | .map(|item| transform_item(item, &bounds)) 122 | .collect(), 123 | ..tr.clone() 124 | }; 125 | quote! { #variant } 126 | } 127 | 128 | // Transforms one item declaration within the definition if it has `async fn` and/or `-> impl Trait` return types by adding new bounds. 129 | fn transform_item(item: &TraitItem, bounds: &Vec) -> TraitItem { 130 | let TraitItem::Fn(fn_item @ TraitItemFn { sig, .. }) = item else { 131 | return item.clone(); 132 | }; 133 | let (arrow, output) = if sig.asyncness.is_some() { 134 | let orig = match &sig.output { 135 | ReturnType::Default => quote! { () }, 136 | ReturnType::Type(_, ty) => quote! { #ty }, 137 | }; 138 | let future = syn::parse2(quote! { ::core::future::Future }).unwrap(); 139 | let ty = Type::ImplTrait(TypeImplTrait { 140 | impl_token: syn::parse2(quote! { impl }).unwrap(), 141 | bounds: iter::once(TypeParamBound::Trait(future)) 142 | .chain(bounds.iter().cloned()) 143 | .collect(), 144 | }); 145 | (syn::parse2(quote! { -> }).unwrap(), ty) 146 | } else { 147 | match &sig.output { 148 | ReturnType::Type(arrow, ty) => match &**ty { 149 | Type::ImplTrait(it) => { 150 | let ty = Type::ImplTrait(TypeImplTrait { 151 | impl_token: it.impl_token, 152 | bounds: it.bounds.iter().chain(bounds).cloned().collect(), 153 | }); 154 | (*arrow, ty) 155 | } 156 | _ => return item.clone(), 157 | }, 158 | ReturnType::Default => return item.clone(), 159 | } 160 | }; 161 | TraitItem::Fn(TraitItemFn { 162 | sig: Signature { 163 | asyncness: None, 164 | output: ReturnType::Type(arrow, Box::new(output)), 165 | ..sig.clone() 166 | }, 167 | ..fn_item.clone() 168 | }) 169 | } 170 | 171 | fn mk_blanket_impl(variant: &Ident, tr: &ItemTrait) -> TokenStream { 172 | let orig = &tr.ident; 173 | let (_impl, orig_ty_generics, _where) = &tr.generics.split_for_impl(); 174 | let items = tr 175 | .items 176 | .iter() 177 | .map(|item| blanket_impl_item(item, variant, orig_ty_generics)); 178 | let blanket_bound: TypeParam = 179 | parse_quote!(TraitVariantBlanketType: #variant #orig_ty_generics); 180 | let blanket = &blanket_bound.ident.clone(); 181 | let mut blanket_generics = tr.generics.clone(); 182 | blanket_generics 183 | .params 184 | .push(GenericParam::Type(blanket_bound)); 185 | let (blanket_impl_generics, _ty, blanket_where_clause) = &blanket_generics.split_for_impl(); 186 | quote! { 187 | impl #blanket_impl_generics #orig #orig_ty_generics for #blanket #blanket_where_clause 188 | { 189 | #(#items)* 190 | } 191 | } 192 | } 193 | 194 | fn blanket_impl_item( 195 | item: &TraitItem, 196 | variant: &Ident, 197 | trait_ty_generics: &TypeGenerics<'_>, 198 | ) -> TokenStream { 199 | // impl IntFactory for T where T: SendIntFactory { 200 | // const NAME: &'static str = ::NAME; 201 | // type MyFut<'a> = ::MyFut<'a> where Self: 'a; 202 | // async fn make(&self, x: u32, y: &str) -> i32 { 203 | // ::make(self, x, y).await 204 | // } 205 | // } 206 | match item { 207 | TraitItem::Const(TraitItemConst { 208 | ident, 209 | generics, 210 | ty, 211 | .. 212 | }) => { 213 | quote! { 214 | const #ident #generics: #ty = ::#ident; 215 | } 216 | } 217 | TraitItem::Fn(TraitItemFn { sig, .. }) => { 218 | let ident = &sig.ident; 219 | let args = sig.inputs.iter().map(|arg| match arg { 220 | FnArg::Receiver(_) => quote! { self }, 221 | FnArg::Typed(PatType { pat, .. }) => match &**pat { 222 | Pat::Ident(arg) => quote! { #arg }, 223 | _ => Error::new_spanned(pat, "patterns are not supported in arguments") 224 | .to_compile_error(), 225 | }, 226 | }); 227 | let maybe_await = if sig.asyncness.is_some() { 228 | quote! { .await } 229 | } else { 230 | quote! {} 231 | }; 232 | quote! { 233 | #sig { 234 | ::#ident(#(#args),*)#maybe_await 235 | } 236 | } 237 | } 238 | TraitItem::Type(TraitItemType { 239 | ident, generics, .. 240 | }) => { 241 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 242 | quote! { 243 | type #ident #impl_generics = ::#ident #ty_generics #where_clause; 244 | } 245 | } 246 | _ => Error::new_spanned(item, "unsupported item type").into_compile_error(), 247 | } 248 | } 249 | --------------------------------------------------------------------------------