├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── README.md ├── examples ├── async.rs ├── collections.rs ├── collections_generics.rs ├── collections_option.rs ├── collections_overloading.rs ├── derive.rs ├── docs.rs ├── fallible.rs ├── generics.rs ├── into.rs ├── multiple.rs ├── multiple_constructors.rs ├── optional.rs ├── returns_self.rs ├── self_builder.rs ├── single.rs ├── try_new.rs └── visibility_override.rs ├── renovate.json ├── src ├── buildstructor │ ├── analyze.rs │ ├── codegen.rs │ ├── lower.rs │ ├── mod.rs │ ├── parse.rs │ ├── snapshots │ │ ├── buildstructor__buildstructor__codegen__tests__associated_types.snap │ │ ├── buildstructor__buildstructor__codegen__tests__async_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__collection_generics_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__collection_generics_test2.snap │ │ ├── buildstructor__buildstructor__codegen__tests__collection_option_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__collection_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__doc.snap │ │ ├── buildstructor__buildstructor__codegen__tests__fallible_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__generic_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__into_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__into_where_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__lifetime.snap │ │ ├── buildstructor__buildstructor__codegen__tests__multi_field_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__multiple_generics_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__option_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__pub_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__reference.snap │ │ ├── buildstructor__buildstructor__codegen__tests__returns_self_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__self_receiver-2.snap │ │ ├── buildstructor__buildstructor__codegen__tests__self_receiver-3.snap │ │ ├── buildstructor__buildstructor__codegen__tests__self_receiver-4.snap │ │ ├── buildstructor__buildstructor__codegen__tests__self_receiver.snap │ │ ├── buildstructor__buildstructor__codegen__tests__self_reference.snap │ │ ├── buildstructor__buildstructor__codegen__tests__single_field_test.snap │ │ ├── buildstructor__buildstructor__codegen__tests__specialization.snap │ │ └── buildstructor__buildstructor__codegen__tests__specialization_self.snap │ └── utils.rs └── lib.rs └── tests ├── buildstructor ├── fail │ ├── duplicate.rs │ ├── duplicate.stderr │ ├── unknown_naming.rs │ └── unknown_naming.stderr └── pass │ ├── associated_types.rs │ ├── async.rs │ ├── collections.rs │ ├── complex_generics.rs │ ├── crate_visibility.rs │ ├── default_builders.rs │ ├── deprecated.rs │ ├── derive.rs │ ├── docs.rs │ ├── entry_exit.rs │ ├── fallible.rs │ ├── generic.rs │ ├── into.rs │ ├── into_where.rs │ ├── lifetime.rs │ ├── multiple_builders.rs │ ├── multiple_constructors.rs │ ├── multiple_fields.rs │ ├── must_use.rs │ ├── naming.rs │ ├── option_field.rs │ ├── returns_self.rs │ ├── self_builder.rs │ ├── single_field.rs │ ├── try_new.rs │ └── visibility_override.rs └── ui.rs /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Continuous integration 4 | 5 | jobs: 6 | check: 7 | name: Check 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - uses: actions-rs/toolchain@v1 12 | with: 13 | profile: minimal 14 | toolchain: stable 15 | override: true 16 | - uses: actions-rs/cargo@v1 17 | with: 18 | command: check 19 | 20 | test: 21 | name: Test Suite 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v4 25 | - uses: actions-rs/toolchain@v1 26 | with: 27 | profile: minimal 28 | toolchain: stable 29 | override: true 30 | - uses: actions-rs/cargo@v1 31 | with: 32 | command: test 33 | 34 | fmt: 35 | name: Rustfmt 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | - uses: actions-rs/toolchain@v1 40 | with: 41 | profile: minimal 42 | toolchain: stable 43 | override: true 44 | - run: rustup component add rustfmt 45 | - uses: actions-rs/cargo@v1 46 | with: 47 | command: fmt 48 | args: --all -- --check 49 | 50 | clippy: 51 | name: Clippy 52 | runs-on: ubuntu-latest 53 | steps: 54 | - uses: actions/checkout@v4 55 | - uses: actions-rs/toolchain@v1 56 | with: 57 | profile: minimal 58 | toolchain: stable 59 | override: true 60 | - run: rustup component add clippy 61 | - uses: actions-rs/cargo@v1 62 | with: 63 | command: clippy 64 | args: -- -D warnings 65 | 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | .idea 4 | .toolversions 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | ## 0.6.0 - 2025-02-13 7 | [#195](https://github.com/BrynCooke/buildstructor/pull/195) 8 | Update clippy lint allow too many args: 9 | ``` 10 | #[allow(clippy::too_many_arguments)] 11 | ``` 12 | 13 | [#197](https://github.com/BrynCooke/buildstructor/pull/197) 14 | Builders methods have `#[must_use]`. This will prevent accidentally unfinished builders. 15 | 16 | ## 0.5.4 - 2023-08-29 17 | [#167](https://github.com/BrynCooke/buildstructor/pull/167) 18 | Remove tild from dependencies 19 | 20 | ## 0.5.3 - 2023-06-21 21 | [#147](https://github.com/BrynCooke/buildstructor/issues/147) 22 | Remove .toolversions 23 | 24 | ## 0.5.2 - 2023-03-19 25 | [#103](https://github.com/BrynCooke/buildstructor/issues/103) 26 | Add docs to generated new when using `#[derive(Builder]`. 27 | 28 | ## 0.5.1 - 2022-11-03 29 | [#96](https://github.com/BrynCooke/buildstructor/issues/96) 30 | Fix associated type parameters: 31 | ```rust 32 | #[buildstructor] 33 | impl Foo { 34 | #[builder] 35 | pub fn new(foo: T, bar: T::Bar) -> Foo { 36 | Foo { foo, bar } 37 | } 38 | } 39 | ``` 40 | 41 | ## 0.5.0 - 2022-08-05 42 | 43 | [#81](https://github.com/BrynCooke/buildstructor/issues/81) 44 | Fix derive builder when used with module level visibility. 45 | 46 | [#77](https://github.com/BrynCooke/buildstructor/issues/77) 47 | Remove validation of visibility specifier. 48 | 49 | [#74](https://github.com/BrynCooke/buildstructor/issues/74) 50 | Automatically add `#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]` to functions annotated with `#[builder]`. 51 | 52 | ## 0.4.0 - 2022-07-31 53 | 54 | [#69](https://github.com/BrynCooke/buildstructor/issues/69) 55 | Add the ability to override the visibility of generated builder. 56 | 57 | ```rust 58 | #[derive(buildstructor::Builder)] 59 | pub struct MyStruct { 60 | simple: usize, 61 | } 62 | ``` 63 | 64 | The generated constructor will have private visibility and the builder will be public. 65 | 66 | [#70](https://github.com/BrynCooke/buildstructor/issues/70) 67 | Add the ability to override the visibility of generated builder. 68 | 69 | [#3](https://github.com/BrynCooke/buildstructor/issues/3) 70 | Changed the storage of required but not yet supplied values to use MaybeUninit. 71 | The tuple that represents the builder state stays the same memory layout regardless of if a field has been initialized or not. 72 | 73 | This does not require any unsafe code! 74 | 75 | ## 0.3.2 - 2022-06-09 76 | 77 | [#60](https://github.com/BrynCooke/buildstructor/issues/55) 78 | Fix impl with concrete types in generics where self is used in the return type. 79 | 80 | ```rust 81 | #[buildstructor] 82 | impl Foo { 83 | #[builder] 84 | fn bound_new(simple: usize) -> Self { 85 | Self { simple } 86 | } 87 | } 88 | ``` 89 | Previously the generated builder method was not including concrete generic type. In this case `usize`. 90 | 91 | 92 | ## 0.3.1 - 2022-06-09 93 | 94 | [#60](https://github.com/BrynCooke/buildstructor/issues/55) 95 | Fix impl with concrete types in generics. 96 | 97 | ```rust 98 | #[buildstructor] 99 | impl Foo { 100 | #[builder] 101 | fn bound_new(simple: usize) -> Foo { 102 | Self { simple } 103 | } 104 | } 105 | ``` 106 | Previously the generated builder method was not including concrete generic type. In this case `usize`. 107 | 108 | ## 0.3.0 - 2022-05-23 109 | 110 | [#55](https://github.com/BrynCooke/buildstructor/issues/55) 111 | Lifetimes are supported now. 112 | 113 | [#52](https://github.com/BrynCooke/buildstructor/issues/52) 114 | Add docs to generated builder. 115 | In addition, a type alias is introduced for the initial builder type so that: 116 | 1. the docs look nice 117 | 2. the builder can be passed to a function (although this is of limited real world use). 118 | 119 | [#4](https://github.com/BrynCooke/buildstructor/issues/4) 120 | Use `#[inline(always)]` on generated code. 121 | 122 | ## 0.2.0 - 2022-05-10 123 | [#45](https://github.com/BrynCooke/buildstructor/issues/45) 124 | Major refactor to expand the scope of buildstructor. 125 | 126 | To provide more control over generated builders and allow builders for methods with receivers the top level annotation has changed: 127 | 128 | `#[buildstructor::builder]` => `#[buildstructor::buildstructor]` 129 | 130 | 1. Annotate the impl with: `#[buildstructor::buildstructor]` 131 | 2. Annotate methods to create a builders for with: `#[builder]` 132 | 133 | ```rust 134 | #[buildstructor::buildstructor] 135 | impl Foo { 136 | #[builder] 137 | fn new(simple: String) -> Foo { 138 | Self { simple } 139 | } 140 | } 141 | ``` 142 | 143 | You can configure your builder using the `#[builder]` annotation, which has the following attributes: 144 | * `entry` => The entry point for your builder. If not specified then the pre-existing rules around `new/*_new` are used. 145 | * `exit` => The terminal method for the generated builder. Defaults to `builder` for constructors and `call` for methods. 146 | 147 | In addition, you can now specify builders on methods that take self: 148 | 149 | ```rust 150 | #[derive(Default)] 151 | pub struct Client; 152 | 153 | #[buildstructor::buildstructor] 154 | impl Client { 155 | #[builder(entry = "phone", exit = "call")] 156 | fn phone_call(self, _simple: String) {} 157 | } 158 | 159 | fn main() { 160 | Client::default().phone().simple("3").call(); 161 | } 162 | ``` 163 | Note, if method parameters begin with `_` then this is stripped for the builder method names. 164 | 165 | ## 0.1.12 - 2022-05-06 166 | [#39](https://github.com/BrynCooke/buildstructor/issues/39) 167 | Visibility of builder now matches the visibility of each constructor. 168 | 169 | ## 0.1.11 - 2022-05-06 170 | [#39](https://github.com/BrynCooke/buildstructor/issues/39) 171 | Visibility of builder now matches the visibility of each constructor. 172 | 173 | [#28](https://github.com/BrynCooke/buildstructor/issues/28) 174 | Generalize replacing of self in return type. 175 | 176 | ## 0.1.10 - 2022-05-04 177 | [#30](https://github.com/BrynCooke/buildstructor/issues/30) 178 | The original token stream is output if there are compile errors. 179 | This allows IDEs to auto complete during periods of invalid code. 180 | 181 | ## 0.1.9 - 2022-04-26 182 | [#24](https://github.com/BrynCooke/buildstructor/issues/24) 183 | Simple types are now given Into treatment globally. 184 | 185 | ## 0.1.8 - 2022-04-25 186 | [#5](https://github.com/BrynCooke/buildstructor/issues/5) 187 | Simple types are now given Into treatment when inserting to collection via singular form. 188 | 189 | ## 0.1.7 - 2022-04-23 190 | [#18](https://github.com/BrynCooke/buildstructor/issues/18) Relaxed collection support. 191 | Collections type matching is relaxed to the following: 192 | 193 | | Type Name | Method used to insert | 194 | |-----------|-----------------------| 195 | | ...Buffer | push(_) | 196 | | ...Deque | push(_) | 197 | | ...Heap | push(_) | 198 | | ...Set | insert(_) | 199 | | ...Stack | push(_) | 200 | | ...Map | insert(_, _) | 201 | | Vec | push(_) | 202 | 203 | ## 0.1.6 - 2022-04-23 204 | [#14](https://github.com/BrynCooke/buildstructor/issues/14) Generics ordering bug. 205 | Generics were not being consistently ordered, which caused issues if there were generics on the impl type and also in a where clause. 206 | 207 | ## 0.1.5 - 2022-04-11 208 | ### Added 209 | [#9](https://github.com/BrynCooke/buildstructor/issues/9) Add `*_new` support. 210 | Any method named `new` or has a suffix `_new` will create a builder. 211 | Builders methods are named appropriately. e.g. `try_new` -> `try_build`. 212 | ### Fixed 213 | [#11](https://github.com/BrynCooke/buildstructor/issues/11) Fix multiple builders in the same module. 214 | Removes the use of wildcard imports to builder modules to fix name clashes. 215 | 216 | [#8](https://github.com/BrynCooke/buildstructor/issues/8) Fix constructors that return `Self` 217 | `Self` on builders needed to be converted to the target type. 218 | 219 | ## 0.1.4 - 2022-03-30 220 | ### Fixed 221 | [#6](https://github.com/BrynCooke/buildstructor/issues/6) Fix generics on collections. 222 | This mostly rolls back the changes in [#1](https://github.com/BrynCooke/buildstructor/issues/1). THe examples have been updated to show the correct way to use into with a collection. 223 | 224 | ## 0.1.3 - 2022-03-30 225 | ### Fixed 226 | [#1](https://github.com/BrynCooke/buildstructor/issues/1) Fix generics on collections 227 | 228 | ## 0.1.2 - 2022-03-30 229 | ### Changed 230 | Improve readme 231 | 232 | Add rust doc to `[builder]` 233 | 234 | ## 0.1.1 - 2022-03-29 235 | 236 | ### Changed 237 | Improve readme 238 | 239 | ## 0.1.0 - 2022-003-29 240 | 241 | ### Added 242 | Initial release 243 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "buildstructor" 3 | version = "0.6.0" 4 | edition = "2021" 5 | authors = ["Bryn Cooke "] 6 | license = "Apache-2.0" 7 | description = "Macro to derive a builder from a constructor function." 8 | homepage = "https://github.com/BrynCooke/buildstructor" 9 | repository = "https://github.com/BrynCooke/buildstructor" 10 | categories = ["development-tools", "rust-patterns"] 11 | keywords = ["derive", "macro", "builder", "constructor"] 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [dependencies] 17 | proc-macro2 = "1.0.66" 18 | quote = "1.0.33" 19 | syn = { version = "2.0.38", features = ["full", "extra-traits"] } 20 | try_match = "0.4.1" 21 | str_inflector = "0.12.0" 22 | 23 | [dev-dependencies] 24 | trybuild = "1.0.84" 25 | tokio = { version = "1", features = ["rt-multi-thread", "macros"] } 26 | insta = "1.31.0" 27 | rust-format = "0.3.4" 28 | http = "1.0.0" 29 | derive_more = { version = "2.0.1", features = ["from"] } 30 | multimap = "0.10.0" 31 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright [2022] [Bryn Cooke] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/bryncooke/buildstructor/workflows/Continuous%20integration/badge.svg)](https://github.com/bryncooke/buildstructor/actions) 2 | [![Latest Version](https://img.shields.io/crates/v/buildstructor.svg)](https://crates.io/crates/buildstructor) 3 | 4 | # Buildstructor 5 | 6 | Derive a builder from constructors/methods using the typesafe builder pattern! 7 | 8 | Use this if your constructor/method has: 9 | * Optional parameters. 10 | * A large number of parameters. 11 | * Collections parameters. 12 | 13 | ## Installation 14 | 15 | Add the dependency to your `Cargo.toml` 16 | ```toml 17 | [dependencies] 18 | buildstructor = "*" 19 | ``` 20 | 21 | ## Usage / Example 22 | 23 | 1. Annotate your `impl` with `#[buildstructor::buildstructor]`. 24 | 2. Annotate your `fn` with `#[builder]`. 25 | 3. Use your automatically derived builder. 26 | 27 | ```rust 28 | pub struct MyStruct { 29 | sum: usize, 30 | } 31 | 32 | #[buildstructor::buildstructor] 33 | impl MyStruct { 34 | #[builder] 35 | fn new(a: usize, b: usize) -> MyStruct { 36 | Self { sum: a + b } 37 | } 38 | 39 | #[builder(entry = "more", exit = "add", visibility="pub")] 40 | fn add_more(&mut self, c: usize, d: usize, e: Option) { 41 | self.sum += c + d + e.unwrap_or(3); 42 | } 43 | } 44 | 45 | fn main() { 46 | let mut mine = MyStruct::builder().a(2).b(3).build(); 47 | assert_eq!(mine.sum, 5); 48 | 49 | mine.more().c(1).d(2).add(); 50 | assert_eq!(mine.sum, 11); 51 | } 52 | ``` 53 | 54 | ## Derive usage 55 | 56 | For simple usage a default constructor and builder may be adequate. 57 | Use `#[derive(buildstructor::Builder)]` to generate `fn new` that is annotated with `#[builder]`. 58 | 59 | ```rust 60 | #[derive(buildstructor::Builder)] 61 | pub struct MyStruct { 62 | simple: usize, 63 | } 64 | 65 | fn main() { 66 | let mut mine = MyStruct::builder().simple(2).build(); 67 | assert_eq!(mine.simple, 2); 68 | } 69 | ``` 70 | 71 | The generated constructor will have private visibility and the builder will match the visibility of the struct. 72 | 73 | ## Motivation 74 | 75 | The difference between this and other builder crates is that constructors/methods can be used to derive builders rather than structs. This results in a more natural fit with regular Rust code, and no annotation magic to define behavior. 76 | 77 | Advantages: 78 | 79 | * You can specify fields in your constructor that do not appear in your struct. 80 | * No magic to default values, just use an `Option` param in your `fn` and default as normal. 81 | * `async` constructors derives `async` builders. 82 | * Fallible constructors (`Result`) derives fallible builders. 83 | * Special `Vec`, `Deque`, `Heap`, `Set`, `Map` support. Add single or multiple items. 84 | * Generated builders can have receiver, `self`, `&self` and `&mut self` are supported. 85 | 86 | This crate is heavily inspired by the excellent [typed-builder](https://github.com/idanarye/rust-typed-builder) crate. It is a good alternative to this crate and well worth considering. 87 | 88 | ## Recipes 89 | 90 | All of these recipes and more can be found in the [examples directory](https://github.com/BrynCooke/buildstructor/tree/main/examples) 91 | 92 | Just write your rust code as usual and annotate the constructor impl with `[builder]` 93 | 94 | ### Constructors 95 | Builders can be generated on methods that have no receiver. 96 | 97 | Configuration: 98 | * `entry` defaults based on `fn` name: 99 | * `new` => `builder` 100 | * `_new` => `_builder` 101 | * `` => cannot be defaulted and must be specified. 102 | * `exit` defaults to `build` 103 | 104 | ```rust 105 | struct MyStruct { 106 | simple: usize 107 | } 108 | 109 | #[buildstructor::buildstructor] 110 | impl MyStruct { 111 | #[builder] 112 | fn new(simple: usize) -> MyStruct { 113 | Self { simple } 114 | } 115 | #[builder] 116 | fn try_new(simple: usize) -> MyStruct { 117 | Self { simple } 118 | } 119 | #[builder(entry = "random", exit = "create")] 120 | fn do_random(simple: usize) -> MyStruct { 121 | Self { simple } 122 | } 123 | } 124 | 125 | fn main() { 126 | let mine = MyStruct::builder().simple(2).build(); 127 | assert_eq!(mine.simple, 2); 128 | 129 | let mine = MyStruct::try_builder().simple(2).build(); 130 | assert_eq!(mine.simple, 2); 131 | 132 | let mine = MyStruct::random().simple(2).create(); 133 | assert_eq!(mine.simple, 2); 134 | } 135 | ``` 136 | 137 | ### Methods 138 | Builders can be generated on methods that take `self`, `&self` and `&mut self` as a parameter. 139 | 140 | Configuration: 141 | * `entry` cannot be defaulted and must be specified. 142 | * `exit` defaults to `call` 143 | 144 | ```rust 145 | use buildstructor::buildstructor; 146 | 147 | #[derive(Default)] 148 | pub struct MyStruct; 149 | 150 | #[buildstructor] 151 | impl MyStruct { 152 | #[builder(entry = "query")] 153 | fn do_query(self, _simple: String) -> bool { 154 | true 155 | } 156 | 157 | #[builder(entry = "query_ref", exit = "stop")] 158 | fn do_query_ref(&self, _simple: String) -> bool { 159 | true 160 | } 161 | 162 | #[builder(entry = "query_ref_mut", exit = "go")] 163 | fn do_query_ref_mut(&mut self, _simple: String) -> bool { 164 | true 165 | } 166 | } 167 | 168 | fn main() { 169 | MyStruct::default().query().simple("3".to_string()).call(); // self 170 | 171 | let mine = MyStruct::default(); 172 | mine.query_ref().simple("3".to_string()).stop(); // &self 173 | 174 | let mut mine = MyStruct::default(); 175 | mine.query_ref_mut().simple("3".to_string()).go(); // &mut self 176 | } 177 | ``` 178 | 179 | ### Optional field 180 | 181 | Fields that are `Option` will also be optional in the builder. You should do defaulting in your constructor. 182 | 183 | ```rust 184 | struct MyStruct { 185 | param: usize 186 | } 187 | 188 | #[buildstructor::buildstructor] 189 | impl MyStruct { 190 | #[builder] 191 | fn new(param: Option) -> MyStruct { 192 | Self { param: param.unwrap_or(3) } 193 | } 194 | } 195 | 196 | fn main() { 197 | let mine = MyStruct::builder().param(2).build(); 198 | assert_eq!(mine.param, 2); 199 | let mine = MyStruct::builder().and_param(Some(2)).build(); 200 | assert_eq!(mine.param, 2); 201 | let mine = MyStruct::builder().build(); 202 | assert_eq!(mine.param, 3); 203 | } 204 | ``` 205 | 206 | Note that if a field is an `Option` or collection then if a user forgets to set it a compile error will be generated. 207 | 208 | ### Into field 209 | 210 | #### Simple types 211 | Types automatically have into conversion if: 212 | * the type is not a scalar. 213 | * the type has no generic parameters. (this may be relaxed later) 214 | * the type is a generic parameter from the impl or constructor method. 215 | 216 | This is useful for Strings, but also other types where you want to overload the singular build method. Create an enum that derives From for all the types you want to support and then use this type in your constructor. 217 | 218 | #### Complex types 219 | You can use generics as usual in your constructor. However, this has the downside of not being able to support optional fields. 220 | 221 | ```rust 222 | struct MyStruct { 223 | param: String 224 | } 225 | 226 | #[buildstructor::buildstructor] 227 | impl MyStruct { 228 | #[builder] 229 | fn new>(param: T) -> MyStruct { 230 | Self { param: param.into() } 231 | } 232 | } 233 | 234 | fn main() { 235 | let mine = MyStruct::builder().param("Hi").build(); 236 | assert_eq!(mine.param, "Hi"); 237 | } 238 | ``` 239 | 240 | ### Async 241 | 242 | To create an `async` builder just make your constructor `async`. 243 | 244 | ```rust 245 | struct MyStruct { 246 | param: usize 247 | } 248 | 249 | #[buildstructor::buildstructor] 250 | impl MyStruct { 251 | #[builder] 252 | async fn new(param: usize) -> MyStruct { 253 | Self { param } 254 | } 255 | } 256 | 257 | #[tokio::main] 258 | async fn main() { 259 | let mine = MyStruct::builder().param(2).build().await; 260 | assert_eq!(mine.param, 2); 261 | } 262 | ``` 263 | 264 | ### Fallible 265 | 266 | To create a fallible builder just make your constructor fallible using `Result`. 267 | 268 | ```rust 269 | use std::error::Error; 270 | struct MyStruct { 271 | param: usize 272 | } 273 | 274 | #[buildstructor::buildstructor] 275 | impl MyStruct { 276 | #[builder] 277 | fn new(param: usize) -> Result> { 278 | Ok(Self { param }) 279 | } 280 | } 281 | 282 | fn main() { 283 | let mine = MyStruct::builder().param(2).build().unwrap(); 284 | assert_eq!(mine.param, 2); 285 | } 286 | ``` 287 | 288 | ### Collections and maps 289 | 290 | Collections and maps are given special treatment, the builder will add additional methods to build the collection one element at a time. 291 | 292 | 293 | ```rust 294 | struct MyStruct { 295 | addresses: Vec 296 | } 297 | 298 | #[buildstructor::buildstructor] 299 | impl MyStruct { 300 | #[builder] 301 | fn new(addresses: Vec) -> MyStruct { 302 | Self { addresses } 303 | } 304 | } 305 | 306 | fn main() { 307 | let mine = MyStruct::builder() 308 | .address("Amsterdam".to_string()) 309 | .address("Fakenham") 310 | .addresses(vec!["Norwich".to_string(), "Bristol".to_string()]) 311 | .build(); 312 | assert_eq!(mine.addresses, vec!["Amsterdam".to_string(), 313 | "Fakenham".to_string(), 314 | "Norwich".to_string(), 315 | "Bristol".to_string()]); 316 | } 317 | ``` 318 | 319 | #### Supported types 320 | Collections are matched by type name: 321 | 322 | | Type Name | Method used to insert | 323 | |-----------|-----------------------| 324 | | ...Buffer | push(_) | 325 | | ...Deque | push(_) | 326 | | ...Heap | push(_) | 327 | | ...Set | insert(_) | 328 | | ...Stack | push(_) | 329 | | ...Map | insert(_, _) | 330 | | Vec | push(_) | 331 | 332 | If your type does not conform to these patterns then you can use a type alias to trick Buildstructor into giving the parameter special treatment. 333 | 334 | #### Naming 335 | 336 | Use the plural form in your constructor argument and `buildstructor` will automatically try to figure out the singular form for individual entry. For instance: 337 | 338 | `addresses` => `address` 339 | 340 | In the case that a singular form cannot be derived automatically the suffix `_entry` will be used. For instance: 341 | 342 | `frodo` => `frodo_entry` 343 | 344 | #### Into 345 | 346 | Adding a singular entry will automatically perform an into conversion if: 347 | * the type is not a scalar. 348 | * the type has no generic parameters. (this may be relaxed later) 349 | * the type is a generic parameter from the impl or constructor method. 350 | 351 | This is useful for Strings, but also other types where you want to overload the singular build method. Create an enum that derives From for all the types you want to support and then use this type in your constructor. 352 | 353 | There had to be some magic somewhere. 354 | 355 | ### Visibility 356 | 357 | Builders will automatically inherit the visibility of the method that they are decorating. However, if you want to override this then you can use the visibility. 358 | 359 | This is useful if you want Buildstructor builders to be the sole entry point for creating your struct. 360 | 361 | ```rust 362 | use std::error::Error; 363 | 364 | pub mod foo { 365 | pub struct MyStruct { 366 | pub param: usize 367 | } 368 | 369 | #[buildstructor::buildstructor] 370 | impl MyStruct { 371 | #[builder(visibility = "pub")] 372 | fn new(param: usize) -> MyStruct { 373 | Self { param } 374 | } 375 | } 376 | } 377 | 378 | fn main() { 379 | let mine = foo::MyStruct::builder().param(2).build(); 380 | assert_eq!(mine.param, 2); 381 | } 382 | ``` 383 | 384 | 385 | ## Upgrade to 0.2.0 386 | 387 | To provide more control over generated builders and allow builders for methods with receivers the top level annotation has changed: 388 | 389 | `#[buildstructor::builder]` => `#[buildstructor::buildstructor]` 390 | 391 | 1. Annotate the impl with: `#[buildstructor::buildstructor]` 392 | 2. Annotate methods to create a builders for with: `#[builder]` 393 | 394 | 395 | ## TODO 396 | * Better error messages. 397 | * More testing. 398 | 399 | PRs welcome! 400 | 401 | ## License 402 | 403 | Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) 404 | 405 | ## Contribution 406 | 407 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as 408 | defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions. 409 | -------------------------------------------------------------------------------- /examples/async.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub struct Async { 4 | simple: usize, 5 | } 6 | 7 | #[buildstructor] 8 | impl Async { 9 | #[builder] 10 | async fn new(simple: usize) -> Async { 11 | Self { simple } 12 | } 13 | } 14 | 15 | #[tokio::main] 16 | async fn main() { 17 | let asc = Async::builder().simple(2).build().await; 18 | assert_eq!(asc.simple, 2); 19 | } 20 | -------------------------------------------------------------------------------- /examples/collections.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | 3 | use buildstructor::buildstructor; 4 | 5 | pub struct Collections { 6 | names: HashSet, 7 | ages: HashMap, 8 | addresses: Vec, 9 | } 10 | 11 | #[buildstructor] 12 | impl Collections { 13 | #[builder] 14 | fn new( 15 | names: HashSet, 16 | ages: HashMap, 17 | addresses: Vec, 18 | ) -> Collections { 19 | Self { 20 | names, 21 | ages, 22 | addresses, 23 | } 24 | } 25 | } 26 | 27 | fn main() { 28 | let collections = Collections::builder() 29 | .name("Nandor".to_string()) 30 | .name("Nandor") 31 | .name("Colin".to_string()) 32 | .names(HashSet::from(["Nadja", "Laszlo"].map(str::to_string))) 33 | .age("Nandor".to_string(), 0) 34 | .age("Nandor", 759) 35 | .age("Colin".to_string(), 100) 36 | .ages(HashMap::from( 37 | [("Nadja", 650), ("Laszlo", 364)].map(|(k, v)| (k.to_string(), v)), 38 | )) 39 | .address("Staten Island".to_string()) 40 | .address("Staten Island") 41 | .addresses(Vec::from(["France", "Turkey"].map(str::to_string))) 42 | .build(); 43 | 44 | assert_eq!( 45 | collections.names, 46 | HashSet::from(["Nandor", "Laszlo", "Nadja", "Colin"].map(str::to_string)) 47 | ); 48 | assert_eq!( 49 | collections.ages, 50 | HashMap::from( 51 | [ 52 | ("Nadja", 650), 53 | ("Laszlo", 364), 54 | ("Colin", 100), 55 | ("Nandor", 759) 56 | ] 57 | .map(|(k, v)| (k.to_string(), v)) 58 | ) 59 | ); 60 | assert_eq!( 61 | collections.addresses, 62 | Vec::from(["Staten Island", "Staten Island", "France", "Turkey"].map(str::to_string)) 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /examples/collections_generics.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | use std::hash::Hash; 3 | 4 | use buildstructor::buildstructor; 5 | 6 | pub struct Collections { 7 | map: HashMap, 8 | set: HashSet, 9 | } 10 | 11 | #[buildstructor] 12 | impl Collections { 13 | #[builder] 14 | fn new + Eq + Hash, V: Into>( 15 | map: HashMap, 16 | set: HashSet, 17 | ) -> Collections { 18 | Self { 19 | map: map.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), 20 | set: set.into_iter().map(|v| v.into()).collect(), 21 | } 22 | } 23 | } 24 | 25 | fn main() { 26 | let collections = Collections::builder() 27 | .map_entry("Appa", "1") 28 | .map_entry("Momo", "2") 29 | .set_entry("Aang") 30 | .set_entry("Katara") 31 | .set_entry("Sokka") 32 | .set_entry("Toph") 33 | .build(); 34 | assert_eq!( 35 | collections.map, 36 | HashMap::from([ 37 | ("Appa".to_string(), "1".to_string()), 38 | ("Momo".to_string(), "2".to_string()) 39 | ]) 40 | ); 41 | assert_eq!( 42 | collections.set, 43 | HashSet::from([ 44 | ("Aang".to_string()), 45 | ("Katara".to_string()), 46 | ("Sokka".to_string()), 47 | ("Toph".to_string()), 48 | ]) 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /examples/collections_option.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use buildstructor::buildstructor; 4 | 5 | pub struct Collections { 6 | map: HashMap, Option>, 7 | } 8 | 9 | #[buildstructor] 10 | impl Collections { 11 | #[builder] 12 | fn new(map: HashMap, Option>) -> Collections { 13 | Self { map } 14 | } 15 | } 16 | 17 | fn main() { 18 | let collections = Collections::builder() 19 | .map_entry(Some("Appa".to_string()), Some("1".to_string())) 20 | .map_entry(Some("Momo".to_string()), Some("2".to_string())) 21 | .build(); 22 | assert_eq!( 23 | collections.map, 24 | HashMap::from([ 25 | (Some("Appa".to_string()), Some("1".to_string())), 26 | (Some("Momo".to_string()), Some("2".to_string())) 27 | ]) 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /examples/collections_overloading.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | use derive_more::From; 3 | use http::header::{HeaderName, CONTENT_TYPE}; 4 | use http::{HeaderMap, HeaderValue}; 5 | use multimap::MultiMap; 6 | use std::error::Error; 7 | 8 | pub struct Collections { 9 | headers: HeaderMap, 10 | } 11 | 12 | #[buildstructor] 13 | impl Collections { 14 | #[builder] 15 | fn new( 16 | headers: MultiMap, 17 | ) -> Result> { 18 | let mut valid_headers = HeaderMap::new(); 19 | for (key, values) in headers { 20 | let header_name: HeaderName = key.try_into()?; 21 | for value in values { 22 | let header_value: HeaderValue = value.try_into()?; 23 | valid_headers.insert(header_name.clone(), header_value); 24 | } 25 | } 26 | 27 | Ok(Self { 28 | headers: valid_headers, 29 | }) 30 | } 31 | } 32 | 33 | #[derive(From, Eq, Hash, PartialEq)] 34 | pub enum IntoHeaderName { 35 | String(String), 36 | HeaderName(HeaderName), 37 | } 38 | 39 | #[derive(From, Eq, Hash, PartialEq)] 40 | pub enum IntoHeaderValue { 41 | String(String), 42 | HeaderValue(HeaderValue), 43 | } 44 | 45 | impl From<&str> for IntoHeaderName { 46 | fn from(name: &str) -> Self { 47 | IntoHeaderName::String(name.to_string()) 48 | } 49 | } 50 | 51 | impl From<&str> for IntoHeaderValue { 52 | fn from(value: &str) -> Self { 53 | IntoHeaderValue::String(value.to_string()) 54 | } 55 | } 56 | 57 | impl TryFrom for HeaderName { 58 | type Error = Box; 59 | 60 | fn try_from(value: IntoHeaderName) -> Result { 61 | Ok(match value { 62 | IntoHeaderName::String(name) => HeaderName::try_from(name)?, 63 | IntoHeaderName::HeaderName(name) => name, 64 | }) 65 | } 66 | } 67 | 68 | impl TryFrom for HeaderValue { 69 | type Error = Box; 70 | 71 | fn try_from(value: IntoHeaderValue) -> Result { 72 | Ok(match value { 73 | IntoHeaderValue::String(value) => HeaderValue::try_from(value)?, 74 | IntoHeaderValue::HeaderValue(value) => value, 75 | }) 76 | } 77 | } 78 | 79 | fn main() { 80 | let collections = Collections::builder() 81 | .header("foo", "bar") 82 | .header(CONTENT_TYPE, "html") 83 | .header("bif".to_string(), "baz".to_string()) 84 | .build() 85 | .unwrap(); 86 | 87 | assert_eq!( 88 | collections.headers.get("foo").unwrap(), 89 | HeaderValue::from_static("bar") 90 | ); 91 | assert_eq!( 92 | collections.headers.get(CONTENT_TYPE).unwrap(), 93 | HeaderValue::from_static("html") 94 | ); 95 | assert_eq!( 96 | collections.headers.get("bif").unwrap(), 97 | HeaderValue::from_static("baz") 98 | ); 99 | } 100 | -------------------------------------------------------------------------------- /examples/derive.rs: -------------------------------------------------------------------------------- 1 | #[derive(buildstructor::Builder)] 2 | pub struct Single { 3 | simple: usize, 4 | } 5 | 6 | mod sub { 7 | #[derive(buildstructor::Builder)] 8 | pub struct Generic { 9 | pub simple: T, 10 | } 11 | } 12 | 13 | fn main() { 14 | let single = Single::builder().simple(2).build(); 15 | assert_eq!(single.simple, 2); 16 | 17 | let generic = sub::Generic::builder().simple(2).build(); 18 | assert_eq!(generic.simple, 2); 19 | } 20 | -------------------------------------------------------------------------------- /examples/docs.rs: -------------------------------------------------------------------------------- 1 | #![warn(missing_docs)] 2 | //! Doc 3 | use buildstructor::{buildstructor, Builder}; 4 | 5 | /// Doc 6 | pub struct Single { 7 | simple1: usize, 8 | simple2: usize, 9 | } 10 | 11 | #[buildstructor] 12 | impl Single { 13 | /// Method description 1 14 | /// Method description 2 15 | /// 16 | /// 17 | /// # Arguments 18 | /// 19 | /// * `simple1`: SimpleArg1 Line1 20 | /// SimpleArg1 Line2 21 | /// * `simple2`: SimpleArg2 Line1 22 | /// SimpleArg2 Line2 23 | /// 24 | /// 25 | /// returns: Single 26 | /// # Examples 27 | /// ``` 28 | /// 29 | /// ``` 30 | #[builder] 31 | pub fn new(simple1: usize, simple2: usize) -> Single { 32 | Self { simple1, simple2 } 33 | } 34 | } 35 | 36 | /// Doc 37 | #[derive(Builder)] 38 | pub struct Double { 39 | /// Simple 1 40 | simple1: usize, 41 | 42 | /// Simple 2 43 | simple2: Option, 44 | } 45 | 46 | fn main() { 47 | let single = Single::builder().simple1(2).simple2(2).build(); 48 | assert_eq!(single.simple1, 2); 49 | assert_eq!(single.simple2, 2); 50 | let double = Double::builder().simple1(1).simple2(2).build(); 51 | assert_eq!(double.simple1, 1); 52 | assert_eq!(double.simple2.unwrap_or_default(), 2); 53 | } 54 | -------------------------------------------------------------------------------- /examples/fallible.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | use std::error::Error; 4 | 5 | pub struct Fallible { 6 | simple: usize, 7 | } 8 | 9 | #[buildstructor] 10 | impl Fallible { 11 | #[builder] 12 | fn new(simple: usize) -> Result> { 13 | Ok(Self { simple }) 14 | } 15 | } 16 | 17 | fn main() { 18 | let fallible = Fallible::builder().simple(2).build().unwrap(); 19 | assert_eq!(fallible.simple, 2); 20 | } 21 | -------------------------------------------------------------------------------- /examples/generics.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub struct Generic { 4 | simple: T, 5 | } 6 | 7 | #[buildstructor] 8 | impl Generic { 9 | #[builder] 10 | fn new(simple: T) -> Generic { 11 | Self { simple } 12 | } 13 | } 14 | 15 | fn main() { 16 | let generic = Generic::builder().simple(2).build(); 17 | assert_eq!(generic.simple, 2); 18 | } 19 | -------------------------------------------------------------------------------- /examples/into.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub struct IntoType { 4 | simple: String, 5 | } 6 | 7 | #[buildstructor] 8 | impl IntoType { 9 | #[builder] 10 | fn new>(simple: T) -> IntoType { 11 | IntoType { 12 | simple: simple.into(), 13 | } 14 | } 15 | } 16 | 17 | fn main() { 18 | let into = IntoType::builder().simple("hi").build(); 19 | assert_eq!(into.simple, "hi"); 20 | } 21 | -------------------------------------------------------------------------------- /examples/multiple.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub struct Multiple { 4 | simple: usize, 5 | simple2: usize, 6 | } 7 | 8 | #[buildstructor] 9 | impl Multiple { 10 | #[builder] 11 | fn new(simple: usize, simple2: usize) -> Multiple { 12 | Self { simple, simple2 } 13 | } 14 | } 15 | fn main() { 16 | let multiple = Multiple::builder().simple(2).simple2(3).build(); 17 | assert_eq!(multiple.simple, 2); 18 | assert_eq!(multiple.simple2, 3); 19 | } 20 | -------------------------------------------------------------------------------- /examples/multiple_constructors.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | use std::error::Error; 4 | 5 | pub struct Multi { 6 | simple: usize, 7 | } 8 | 9 | #[buildstructor] 10 | impl Multi { 11 | #[builder] 12 | fn new(simple: usize) -> Multi { 13 | Self { simple } 14 | } 15 | 16 | #[builder] 17 | fn try_new(simple: usize) -> Result> { 18 | Ok(Self { simple }) 19 | } 20 | 21 | #[builder] 22 | fn maybe_new(simple: usize) -> Option { 23 | Some(Self { simple }) 24 | } 25 | } 26 | 27 | fn main() { 28 | let regular = Multi::builder().simple(2).build(); 29 | assert_eq!(regular.simple, 2); 30 | 31 | let fallible = Multi::try_builder().simple(2).build().unwrap(); 32 | assert_eq!(fallible.simple, 2); 33 | 34 | let option = Multi::maybe_builder().simple(2).build().unwrap(); 35 | assert_eq!(option.simple, 2); 36 | } 37 | -------------------------------------------------------------------------------- /examples/optional.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub struct Optional { 4 | simple: Option, 5 | } 6 | 7 | #[buildstructor] 8 | impl Optional { 9 | #[builder] 10 | fn new(simple: Option) -> Optional { 11 | Self { simple } 12 | } 13 | } 14 | 15 | #[tokio::main] 16 | async fn main() { 17 | let optional = Optional::builder().simple(2).build(); 18 | assert_eq!(optional.simple, Some(2)); 19 | let optional = Optional::builder().and_simple(Some(2)).build(); 20 | assert_eq!(optional.simple, Some(2)); 21 | let optional = Optional::builder().build(); 22 | assert_eq!(optional.simple, None); 23 | } 24 | -------------------------------------------------------------------------------- /examples/returns_self.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub struct ReturnsSelf { 4 | simple: usize, 5 | } 6 | 7 | #[buildstructor] 8 | impl ReturnsSelf { 9 | #[builder] 10 | fn new(simple: usize) -> Self { 11 | Self { simple } 12 | } 13 | } 14 | 15 | fn main() { 16 | let generic = ReturnsSelf::builder().simple(2).build(); 17 | assert_eq!(generic.simple, 2); 18 | } 19 | -------------------------------------------------------------------------------- /examples/self_builder.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | #[derive(Default)] 4 | pub struct Client; 5 | 6 | #[buildstructor] 7 | impl Client { 8 | #[builder(entry = "message", exit = "send")] 9 | fn call_with_no_return(self, _simple: String) {} 10 | 11 | #[builder(entry = "message_ref", exit = "send")] 12 | fn call_with_no_return_ref(&self, _simple: String) {} 13 | 14 | #[builder(entry = "message_ref_mut", exit = "send")] 15 | fn call_with_no_return_ref_mut(&mut self, _simple: String) {} 16 | 17 | #[builder(entry = "query", exit = "call")] 18 | fn call_with_return(self, _simple: String) -> bool { 19 | true 20 | } 21 | 22 | #[builder(entry = "query_ref", exit = "call")] 23 | fn call_with_return_ref(&self, _simple: String) -> bool { 24 | true 25 | } 26 | 27 | #[builder(entry = "query_ref_mut", exit = "call")] 28 | fn call_with_return_ref_mut(&mut self, _simple: String) -> bool { 29 | true 30 | } 31 | } 32 | 33 | fn main() { 34 | Client.message().simple("3".to_string()).send(); 35 | Client.query().simple("3".to_string()).call(); 36 | 37 | let client = Client; 38 | client.message_ref().simple("3".to_string()).send(); 39 | client.query_ref().simple("3".to_string()).call(); 40 | 41 | let mut client = Client; 42 | client.message_ref_mut().simple("3".to_string()).send(); 43 | client.query_ref_mut().simple("3".to_string()).call(); 44 | } 45 | -------------------------------------------------------------------------------- /examples/single.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub struct Single { 4 | simple: usize, 5 | } 6 | 7 | #[buildstructor] 8 | impl Single { 9 | #[builder] 10 | fn new(simple: usize) -> Single { 11 | Self { simple } 12 | } 13 | } 14 | 15 | fn main() { 16 | let single = Single::builder().simple(2).build(); 17 | assert_eq!(single.simple, 2); 18 | } 19 | -------------------------------------------------------------------------------- /examples/try_new.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | use std::error::Error; 4 | 5 | pub struct Fallible { 6 | simple: usize, 7 | } 8 | 9 | #[buildstructor] 10 | impl Fallible { 11 | #[builder] 12 | fn try_new(simple: usize) -> Result> { 13 | Ok(Self { simple }) 14 | } 15 | } 16 | 17 | fn main() { 18 | let fallible = Fallible::try_builder().simple(2).build().unwrap(); 19 | assert_eq!(fallible.simple, 2); 20 | } 21 | -------------------------------------------------------------------------------- /examples/visibility_override.rs: -------------------------------------------------------------------------------- 1 | mod sub1 { 2 | pub(crate) struct Foo { 3 | pub simple: Bar1, 4 | } 5 | 6 | pub(crate) struct Bar1 { 7 | pub(crate) simple: usize, 8 | } 9 | 10 | #[buildstructor::buildstructor] 11 | impl Foo { 12 | #[builder(visibility = "pub (crate)")] 13 | fn new(simple: Bar1) -> Self { 14 | Self { simple } 15 | } 16 | } 17 | } 18 | 19 | mod sub2 { 20 | pub struct Foo { 21 | pub simple: Bar2, 22 | } 23 | 24 | pub struct Bar2 { 25 | pub(crate) simple: usize, 26 | } 27 | 28 | #[buildstructor::buildstructor] 29 | impl Foo { 30 | #[builder(visibility = "pub")] 31 | fn new(simple: Bar2) -> Self { 32 | Self { simple } 33 | } 34 | } 35 | } 36 | 37 | fn main() { 38 | let sub1 = sub1::Foo::builder() 39 | .simple(sub1::Bar1 { simple: 1 }) 40 | .build(); 41 | let sub2 = sub2::Foo::builder() 42 | .simple(sub2::Bar2 { simple: 2 }) 43 | .build(); 44 | 45 | assert_eq!(sub1.simple.simple, 1); 46 | assert_eq!(sub2.simple.simple, 2); 47 | } 48 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/buildstructor/analyze.rs: -------------------------------------------------------------------------------- 1 | use crate::buildstructor::utils::TypeExt; 2 | use proc_macro2::Span; 3 | use quote::format_ident; 4 | use syn::parse::{Parse, ParseStream}; 5 | use syn::spanned::Spanned; 6 | use syn::{ 7 | Attribute, Expr, ExprLit, FnArg, Generics, Ident, ImplItem, ImplItemFn, ItemImpl, Lit, Meta, 8 | MetaNameValue, Result, ReturnType, Token, Type, Visibility, 9 | }; 10 | 11 | use crate::parse::Ast; 12 | pub struct BuilderModel { 13 | pub impl_name: Ident, 14 | pub impl_generics: Generics, 15 | pub delegate_name: Ident, 16 | pub delegate_generics: Generics, 17 | pub delegate_args: Vec, 18 | pub delegate_return_type: ReturnType, 19 | pub is_async: bool, 20 | pub vis: Visibility, 21 | pub config: BuilderConfig, 22 | pub attributes: Vec, 23 | pub self_ty: Box, 24 | } 25 | 26 | #[derive(Debug, Clone, Default)] 27 | pub struct BuildstructorConfig {} 28 | 29 | impl Parse for BuildstructorConfig { 30 | fn parse(_input: ParseStream) -> Result { 31 | Ok(BuildstructorConfig::default()) 32 | } 33 | } 34 | 35 | #[derive(Default)] 36 | pub struct BuilderConfig { 37 | pub entry: Option, 38 | pub exit: Option, 39 | pub span: Option, 40 | pub visibility: Option, 41 | } 42 | impl Parse for BuilderConfig { 43 | fn parse(input: ParseStream) -> Result { 44 | let mut config = BuilderConfig { 45 | span: Some(input.span()), 46 | ..Default::default() 47 | }; 48 | for name_value in input.parse_terminated(MetaNameValue::parse, Token![,])? { 49 | let name = name_value 50 | .path 51 | .get_ident() 52 | .expect("config ident must be preset, qed"); 53 | let value = &name_value.value; 54 | match (name.to_string().as_str(), value) { 55 | ("entry", Expr::Lit(ExprLit{lit:Lit::Str(value), ..})) => { 56 | config.entry = Some(value.value()); 57 | } 58 | ("exit", Expr::Lit(ExprLit{lit:Lit::Str(value), ..})) => { 59 | config.exit = Some(value.value()); 60 | } 61 | ("visibility", Expr::Lit(ExprLit{lit:Lit::Str(value), ..})) => { 62 | let value = value.value(); 63 | config.visibility = Some(value); 64 | } 65 | _ => return Err(syn::Error::new( 66 | value.span(), 67 | format!("invalid builder attribute '{}', only 'entry', 'exit' and 'visibility' are allowed and their type must be string", name), 68 | )), 69 | } 70 | } 71 | 72 | Ok(config) 73 | } 74 | } 75 | 76 | pub fn analyze(legacy_default_builders: bool, ast: &Ast) -> Result>> { 77 | let methods = get_eligible_methods(&ast.item, legacy_default_builders); 78 | let ident = ast 79 | .item 80 | .self_ty 81 | .raw_ident() 82 | .ok_or_else(|| syn::Error::new(ast.item.span(), "cannot find name of struct"))?; 83 | let models = methods 84 | .into_iter() 85 | .map(|(builder, config)| { 86 | Ok(BuilderModel { 87 | impl_name: ident.clone(), 88 | impl_generics: ast.item.generics.clone(), 89 | self_ty: ast.item.self_ty.clone(), 90 | delegate_name: builder.sig.ident.clone(), 91 | delegate_generics: builder.sig.generics.clone(), 92 | delegate_args: builder.sig.inputs.clone().into_iter().collect(), 93 | delegate_return_type: builder.sig.output.clone(), 94 | is_async: builder.sig.asyncness.is_some(), 95 | vis: builder.vis.clone(), 96 | config: config?, 97 | attributes: builder.attrs.clone(), 98 | }) 99 | }) 100 | .collect(); 101 | 102 | Ok(models) 103 | } 104 | 105 | fn get_eligible_methods( 106 | item: &ItemImpl, 107 | default_builders: bool, 108 | ) -> Vec<(&ImplItemFn, Result)> { 109 | item.items 110 | .iter() 111 | .filter_map(|item| { 112 | let builder_attr = Some(format_ident!("builder")); 113 | if let ImplItem::Fn(method) = item { 114 | if let Some(attr) = method 115 | .attrs 116 | .iter() 117 | .find(|attr| attr.path().get_ident() == builder_attr.as_ref()) 118 | { 119 | return Some((method, { 120 | match attr.meta { 121 | Meta::List(_) => attr.parse_args(), 122 | _ => Ok(BuilderConfig::default()), 123 | } 124 | })); 125 | } else if default_builders { 126 | // If the method doesn't have a receiver and it matches the new pattern. 127 | let method_name = method.sig.ident.to_string(); 128 | if !matches!(method.sig.inputs.iter().next(), Some(FnArg::Receiver(_))) 129 | && method_name.ends_with("_new") 130 | || method_name.eq("new") 131 | { 132 | return Some((method, Ok(BuilderConfig::default()))); 133 | } 134 | } 135 | } 136 | None 137 | }) 138 | .collect() 139 | } 140 | 141 | #[cfg(test)] 142 | mod tests { 143 | use super::*; 144 | use crate::buildstructor::tests::*; 145 | 146 | #[test] 147 | fn single_field_test() { 148 | analyze(false, &single_field_test_case()).unwrap(); 149 | } 150 | 151 | #[test] 152 | fn pub_test() { 153 | analyze(false, &pub_test_case()).unwrap(); 154 | } 155 | 156 | #[test] 157 | fn multi_field_test() { 158 | analyze(false, &multi_field_test_case()).unwrap(); 159 | } 160 | 161 | #[test] 162 | fn generic_test() { 163 | analyze(false, &generic_test_case()).unwrap(); 164 | } 165 | 166 | #[test] 167 | fn async_test() { 168 | analyze(false, &async_test_case()).unwrap(); 169 | } 170 | 171 | #[test] 172 | fn fallible_test() { 173 | analyze(false, &fallible_test_case()).unwrap(); 174 | } 175 | 176 | #[test] 177 | fn into_test() { 178 | analyze(false, &into_test_case()).unwrap(); 179 | } 180 | 181 | #[test] 182 | fn into_where_test() { 183 | analyze(false, &into_where_test_case()).unwrap(); 184 | } 185 | 186 | #[test] 187 | fn option_test() { 188 | analyze(false, &option_test_case()).unwrap(); 189 | } 190 | 191 | #[test] 192 | fn collection_test() { 193 | analyze(false, &collections_test_case()).unwrap(); 194 | } 195 | 196 | #[test] 197 | fn collection_generics_test() { 198 | analyze(false, &collections_generics_test_case()).unwrap(); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/buildstructor/lower.rs: -------------------------------------------------------------------------------- 1 | use crate::analyze::BuilderModel; 2 | use crate::buildstructor::utils::{IdentExt, PunctuatedExt, TypeExt}; 3 | use proc_macro2::{Ident, TokenStream}; 4 | use quote::{format_ident, quote}; 5 | use std::default::Default; 6 | use syn::punctuated::Punctuated; 7 | use syn::{Attribute, TypeReference}; 8 | use syn::{ 9 | Expr, ExprField, FnArg, GenericArgument, GenericParam, Generics, Index, Member, Pat, 10 | PathArguments, Receiver, Result, ReturnType, Type, TypeParam, TypeTuple, VisRestricted, 11 | Visibility, 12 | }; 13 | use try_match::try_match; 14 | 15 | pub struct Ir { 16 | pub module_name: Ident, 17 | pub impl_name: Ident, 18 | pub impl_generics: Generics, 19 | pub delegate_name: Ident, 20 | pub delegate_generics: Generics, 21 | pub builder_name: Ident, 22 | pub builder_fields: Vec, 23 | pub builder_return_type: ReturnType, 24 | pub builder_vis: Visibility, 25 | pub builder_generics: Generics, 26 | pub builder_entry: Ident, 27 | pub builder_exit: Ident, 28 | pub vis: Visibility, 29 | pub is_async: bool, 30 | pub receiver: Option, 31 | pub doc: Vec, 32 | pub implicit_lifetime: bool, 33 | pub self_ty: Box, 34 | } 35 | 36 | pub struct BuilderField { 37 | pub name: Ident, 38 | pub field_type: FieldType, 39 | pub ty: Type, 40 | pub ty_into: bool, 41 | pub generic_types: GenericTypes, 42 | } 43 | 44 | #[derive(Debug)] 45 | pub enum FieldType { 46 | Regular, 47 | Option, 48 | Vec, 49 | Set, 50 | Map, 51 | } 52 | 53 | pub fn lower(model: BuilderModel) -> Result { 54 | // Either visibility is set explicitly or we default to super. 55 | let vis = builder_visibility(&model, &model.vis, &model.vis)?; 56 | let builder_vis = builder_visibility( 57 | &model, 58 | &model.vis, 59 | &Visibility::Restricted(VisRestricted { 60 | pub_token: Default::default(), 61 | paren_token: Default::default(), 62 | in_token: None, 63 | path: Box::new(format_ident!("super").to_path()), 64 | }), 65 | )?; 66 | let receiver = receiver(&model); 67 | Ok(Ir { 68 | vis, 69 | builder_vis, 70 | module_name: format_ident!( 71 | "__{}_{}_builder", 72 | model.impl_name.to_string().to_lowercase(), 73 | model.delegate_name.to_string().to_lowercase() 74 | ), 75 | impl_name: model.impl_name.clone(), 76 | impl_generics: model.impl_generics.clone(), 77 | self_ty: model.self_ty.clone(), 78 | delegate_name: model.delegate_name.clone(), 79 | delegate_generics: model.delegate_generics.clone(), 80 | builder_name: format_ident!("__{}Builder", model.impl_name), 81 | builder_return_type: builder_return_type(&model.delegate_return_type, &model.self_ty), 82 | builder_entry: builder_entry(&model, &receiver)?, 83 | builder_exit: builder_exit(&model, &receiver), 84 | builder_fields: builder_fields(&model), 85 | builder_generics: Ir::builder_generics(), 86 | is_async: model.is_async, 87 | doc: extract_docs(&model.attributes), 88 | implicit_lifetime: implicit_lifetime(&model), 89 | receiver, 90 | }) 91 | } 92 | 93 | // If the first parameter of a function is a reference it will have an implicit lifetime. 94 | fn implicit_lifetime(model: &BuilderModel) -> bool { 95 | match model.delegate_args.first() { 96 | None => {} 97 | Some(arg) => match arg { 98 | FnArg::Receiver(Receiver { 99 | // If the lifetime has been set explicitly we can ignore it. 100 | reference: Some((_, None)), 101 | .. 102 | }) => return true, 103 | FnArg::Typed(arg) => { 104 | if let Type::Reference(TypeReference { lifetime: None, .. }) = *arg.ty { 105 | return true; 106 | } 107 | } 108 | _ => {} 109 | }, 110 | } 111 | false 112 | } 113 | 114 | fn extract_docs(attributes: &[Attribute]) -> Vec { 115 | let doc_ident = format_ident!("doc"); 116 | attributes 117 | .iter() 118 | .filter(|a| a.path().get_ident() == Some(&doc_ident)) 119 | .cloned() 120 | .collect() 121 | } 122 | 123 | fn receiver(model: &BuilderModel) -> Option { 124 | model 125 | .delegate_args 126 | .iter() 127 | .filter_map(|a| match a { 128 | FnArg::Receiver(r) => Some(r.clone()), 129 | FnArg::Typed(_) => None, 130 | }) 131 | .next() 132 | } 133 | 134 | fn builder_visibility( 135 | model: &BuilderModel, 136 | visibility: &Visibility, 137 | default: &Visibility, 138 | ) -> Result { 139 | // Either visibility is set explicitly or we default to super. 140 | Ok(if let Some(visibility) = &model.config.visibility { 141 | if visibility.trim().is_empty() { 142 | default.clone() 143 | } else { 144 | syn::parse_str(visibility)? 145 | } 146 | } else if let Visibility::Inherited = model.vis { 147 | default.clone() 148 | } else { 149 | visibility.clone() 150 | }) 151 | } 152 | 153 | fn builder_return_type(return_type: &ReturnType, target: &Type) -> ReturnType { 154 | let mut return_type = return_type.clone(); 155 | if let ReturnType::Type(_, ty) = &mut return_type { 156 | replace_self(ty, target); 157 | } 158 | return_type 159 | } 160 | 161 | fn replace_self(ty: &mut Type, target: &Type) { 162 | let self_type = format_ident!("Self").to_type_path(); 163 | if let (Type::Path(path), Type::Path(self_ty)) = (ty, target) { 164 | if path == &self_type { 165 | *path = self_ty.clone(); 166 | } else { 167 | for segment in path.path.segments.iter_mut() { 168 | if let PathArguments::AngleBracketed(args) = &mut segment.arguments { 169 | for mut arg in args.args.iter_mut() { 170 | if let GenericArgument::Type(ty) = &mut arg { 171 | replace_self(ty, target); 172 | } 173 | } 174 | } 175 | } 176 | } 177 | } 178 | } 179 | 180 | fn builder_fields(model: &BuilderModel) -> Vec { 181 | model 182 | .delegate_args 183 | .iter() 184 | .filter_map(|f| match f { 185 | FnArg::Typed(t) => { 186 | let ident = try_match!(&*t.pat, Pat::Ident(x)=>x).ok()?; 187 | let field_type = field_type(&t.ty); 188 | 189 | let generic_types = generic_types(model, &field_type, &t.ty); 190 | 191 | let into = 192 | t.ty.is_into_capable(&model.impl_generics, &model.delegate_generics); 193 | Some(BuilderField { 194 | ty: *t.ty.clone(), 195 | ty_into: into, 196 | name: ident 197 | .ident 198 | .to_string() 199 | .strip_prefix('_') 200 | .map(|stripped| format_ident!("{}", stripped)) 201 | .unwrap_or_else(|| ident.ident.clone()), 202 | field_type, 203 | generic_types, 204 | }) 205 | } 206 | FnArg::Receiver(_) => None, 207 | }) 208 | .collect() 209 | } 210 | 211 | #[derive(Default)] 212 | pub struct GenericTypes { 213 | pub key_type: Option, 214 | pub key_into: bool, 215 | pub value_type: Option, 216 | pub value_into: bool, 217 | pub generic_type: Option, 218 | pub generic_into: bool, 219 | } 220 | 221 | fn generic_types(model: &BuilderModel, field_type: &FieldType, ty: &Type) -> GenericTypes { 222 | let args = ty.generic_args(); 223 | match ( 224 | &field_type, 225 | args.and_then(|args| args.iter().next()), 226 | args.and_then(|args| args.iter().nth(1)), 227 | ) { 228 | ( 229 | FieldType::Option | FieldType::Vec | FieldType::Set, 230 | Some(GenericArgument::Type(collection_type)), 231 | None, 232 | ) => GenericTypes { 233 | generic_type: Some(collection_type.clone()), 234 | generic_into: collection_type 235 | .is_into_capable(&model.impl_generics, &model.delegate_generics), 236 | ..Default::default() 237 | }, 238 | ( 239 | FieldType::Map, 240 | Some(GenericArgument::Type(key_type)), 241 | Some(GenericArgument::Type(value_type)), 242 | ) => GenericTypes { 243 | key_type: Some(key_type.clone()), 244 | key_into: key_type.is_into_capable(&model.impl_generics, &model.delegate_generics), 245 | value_type: Some(value_type.clone()), 246 | value_into: value_type.is_into_capable(&model.impl_generics, &model.delegate_generics), 247 | ..Default::default() 248 | }, 249 | _ => GenericTypes::default(), 250 | } 251 | } 252 | 253 | fn builder_entry(model: &BuilderModel, receiver: &Option) -> Result { 254 | let method_name = model.delegate_name.to_string(); 255 | match (&model.config.entry, receiver) { 256 | (Some(name), _) => return Ok(format_ident!("{}", name)), 257 | // constructor 258 | (None, None) => match (method_name.as_str(), method_name.strip_suffix("_new")) { 259 | ("new", _) => return Ok(format_ident!("builder")), 260 | (_, Some(stripped)) => return Ok(format_ident!("{}_builder", stripped)), 261 | _ => {} 262 | }, 263 | _ => {} 264 | } 265 | Err(syn::Error::new( 266 | model 267 | .config 268 | .span 269 | .unwrap_or_else(|| model.delegate_name.span()), 270 | format!( 271 | "#[builder(entry = \"\")] cannot be defaulted for 'fn {}' and must be specified via annotation", method_name 272 | ), 273 | )) 274 | } 275 | 276 | fn builder_exit(model: &BuilderModel, receiver: &Option) -> Ident { 277 | match (&model.config.exit, receiver) { 278 | (Some(name), _) => format_ident!("{}", name), 279 | // constructor 280 | (None, None) => format_ident!("build"), 281 | // call 282 | (None, Some(_)) => format_ident!("call"), 283 | } 284 | } 285 | 286 | fn field_type(ty: &Type) -> FieldType { 287 | match ty.raw_ident() { 288 | Some(f) if f == format_ident!("Option") => FieldType::Option, 289 | Some(f) if f == format_ident!("Vec") => FieldType::Vec, 290 | Some(f) if f.to_string().ends_with("Stack") => FieldType::Vec, 291 | Some(f) if f.to_string().ends_with("Heap") => FieldType::Vec, 292 | Some(f) if f.to_string().ends_with("Deque") => FieldType::Vec, 293 | Some(f) if f.to_string().ends_with("Buffer") => FieldType::Vec, 294 | Some(f) if f.to_string().ends_with("Set") => FieldType::Set, 295 | Some(f) if f.to_string().ends_with("Map") => FieldType::Map, 296 | _ => FieldType::Regular, 297 | } 298 | } 299 | 300 | impl Ir { 301 | pub fn delegate_args(&self) -> Vec { 302 | self.builder_fields 303 | .iter() 304 | .enumerate() 305 | .map(|(idx, _)| { 306 | let idx = Index::from(idx); 307 | quote! { 308 | self.fields.#idx.into().value 309 | } 310 | }) 311 | .collect() 312 | } 313 | 314 | pub fn tuple_field(&self, idx: usize) -> Expr { 315 | Expr::Field(ExprField { 316 | attrs: vec![], 317 | base: Box::new(Self::fields()), 318 | dot_token: Default::default(), 319 | member: Member::Unnamed(Index::from(idx)), 320 | }) 321 | } 322 | 323 | pub fn fields() -> Expr { 324 | Expr::Field(ExprField { 325 | attrs: vec![], 326 | base: Box::new(Expr::Path(format_ident!("self").to_expr_path())), 327 | dot_token: Default::default(), 328 | member: Member::Named(format_ident!("fields")), 329 | }) 330 | } 331 | 332 | pub fn builder_state_type_initial(&self) -> Type { 333 | Type::Tuple(TypeTuple { 334 | paren_token: Default::default(), 335 | elems: Punctuated::from_iter(self.builder_fields.iter().map(|field| { 336 | match field.field_type { 337 | FieldType::Regular => field.ty.wrap_in_generic_with_module( 338 | &self.module_name, 339 | format_ident!("__Required"), 340 | ), 341 | _ => field.ty.wrap_in_generic_with_module( 342 | &self.module_name, 343 | format_ident!("__Optional"), 344 | ), 345 | } 346 | })) 347 | .with_trailing(), 348 | }) 349 | } 350 | 351 | pub fn builder_state_initial(&self) -> Vec { 352 | self.builder_fields 353 | .iter() 354 | .map(|field| match field.field_type { 355 | FieldType::Regular => quote! {__required()}, 356 | _ => quote! {__optional()}, 357 | }) 358 | .collect() 359 | } 360 | 361 | pub fn param_generics(&self) -> Generics { 362 | Generics { 363 | params: Punctuated::from_iter(self.builder_fields.iter().enumerate().map( 364 | |(idx, f)| { 365 | format_ident!("__P{}", idx).to_generic_param(Some( 366 | &f.ty 367 | .wrap_in_generic(format_ident!("__Set")) 368 | .wrap_in_generic(format_ident!("Into")), 369 | )) 370 | }, 371 | )), 372 | ..Default::default() 373 | } 374 | } 375 | 376 | fn builder_generics() -> Generics { 377 | Generics { 378 | params: Punctuated::from_iter(vec![format_ident!("__P").to_generic_param(None)]), 379 | ..Default::default() 380 | } 381 | } 382 | 383 | pub fn builder_type_generics(&self) -> Generics { 384 | Generics { 385 | params: Punctuated::from_iter( 386 | self.builder_fields.iter().enumerate().map(|(idx, _f)| { 387 | GenericParam::Type(TypeParam::from(format_ident!("__{}", idx))) 388 | }), 389 | ), 390 | ..Default::default() 391 | } 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /src/buildstructor/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod analyze; 2 | pub mod codegen; 3 | pub mod lower; 4 | pub mod parse; 5 | pub mod utils; 6 | 7 | #[cfg(test)] 8 | mod tests { 9 | use crate::parse::Ast; 10 | use syn::parse_quote; 11 | 12 | pub fn single_field_test_case() -> Ast { 13 | parse_quote!( 14 | #[buildstructor] 15 | impl Foo { 16 | #[builder] 17 | fn new(simple: usize) -> Foo { 18 | Self { simple } 19 | } 20 | } 21 | ) 22 | } 23 | 24 | pub fn pub_test_case() -> Ast { 25 | parse_quote!( 26 | #[buildstructor] 27 | impl Foo { 28 | #[builder] 29 | pub fn new(simple: usize) -> Foo { 30 | Self { simple } 31 | } 32 | } 33 | ) 34 | } 35 | 36 | pub fn multi_field_test_case() -> Ast { 37 | parse_quote!( 38 | #[buildstructor] 39 | impl Foo { 40 | #[builder] 41 | fn new(simple: usize, simple2: usize) -> Foo { 42 | Self { simple, simple2 } 43 | } 44 | } 45 | ) 46 | } 47 | 48 | pub fn fallible_test_case() -> Ast { 49 | parse_quote!( 50 | #[buildstructor] 51 | impl Foo { 52 | #[builder] 53 | fn new(simple: usize) -> Result { 54 | Ok(Self { simple }) 55 | } 56 | } 57 | ) 58 | } 59 | 60 | pub fn async_test_case() -> Ast { 61 | parse_quote!( 62 | #[buildstructor] 63 | impl Foo { 64 | #[builder] 65 | async fn new(simple: usize) -> Foo { 66 | Foo { simple } 67 | } 68 | } 69 | ) 70 | } 71 | 72 | pub fn generic_test_case() -> Ast { 73 | parse_quote!( 74 | #[buildstructor] 75 | impl Foo { 76 | #[builder] 77 | fn new(simple: T) -> Foo { 78 | Self { simple } 79 | } 80 | } 81 | ) 82 | } 83 | 84 | pub fn into_test_case() -> Ast { 85 | parse_quote!( 86 | #[buildstructor] 87 | impl Foo { 88 | #[builder] 89 | fn new>(simple: T) -> Foo { 90 | Foo { 91 | simple: simple.into(), 92 | } 93 | } 94 | } 95 | ) 96 | } 97 | 98 | pub fn into_where_test_case() -> Ast { 99 | parse_quote!( 100 | #[buildstructor] 101 | impl Foo { 102 | #[builder] 103 | fn new(simple: T) -> Foo 104 | where 105 | T: Into, 106 | { 107 | Foo { 108 | simple: simple.into(), 109 | } 110 | } 111 | } 112 | ) 113 | } 114 | 115 | pub fn option_test_case() -> Ast { 116 | parse_quote!( 117 | #[buildstructor] 118 | impl Foo { 119 | #[builder] 120 | fn new(option: Option) -> Foo { 121 | Foo { option } 122 | } 123 | } 124 | ) 125 | } 126 | 127 | pub fn collections_test_case() -> Ast { 128 | parse_quote!( 129 | #[buildstructor] 130 | impl Foo { 131 | #[builder] 132 | fn new( 133 | simple: usize, 134 | set: HashSet, 135 | map: HashMap, 136 | vec: Vec, 137 | btmap: BTreeMap, 138 | btset: BTreeSet, 139 | ) -> Foo { 140 | Self { 141 | simple, 142 | set, 143 | map, 144 | vec, 145 | btmap, 146 | btset, 147 | } 148 | } 149 | } 150 | ) 151 | } 152 | 153 | pub fn collections_generics_test_case() -> Ast { 154 | parse_quote!( 155 | #[buildstructor] 156 | impl Foo { 157 | #[builder] 158 | fn new + Eq + Hash, V: Into>(param: HashMap) -> Foo { 159 | Self { 160 | param: param 161 | .into_iter() 162 | .map(|(k, v)| (k.into(), v.into())) 163 | .collect(), 164 | } 165 | } 166 | } 167 | ) 168 | } 169 | 170 | pub fn collections_option_test_case() -> Ast { 171 | parse_quote!( 172 | #[buildstructor] 173 | impl Foo { 174 | #[builder] 175 | fn new(param: HashMap, Option>) -> Foo { 176 | Self { 177 | param: param 178 | .into_iter() 179 | .map(|(k, v)| (k.into(), v.into())) 180 | .collect(), 181 | } 182 | } 183 | } 184 | ) 185 | } 186 | 187 | pub fn returns_self_test_case() -> Ast { 188 | parse_quote!( 189 | #[buildstructor] 190 | impl Foo { 191 | #[builder] 192 | fn new(simple: usize) -> Self { 193 | Self { simple } 194 | } 195 | } 196 | ) 197 | } 198 | 199 | pub fn multiple_generics_test_case() -> Ast { 200 | parse_quote!( 201 | #[buildstructor] 202 | impl Request { 203 | #[builder] 204 | pub fn fake_new( 205 | headers: Vec<(K, V)>, 206 | uri: Option, 207 | method: Option, 208 | body: T, 209 | ) -> http::Result> 210 | where 211 | HeaderName: TryFrom, 212 | >::Error: Into, 213 | HeaderValue: TryFrom, 214 | >::Error: Into, 215 | { 216 | let mut builder = http::request::Builder::new(); 217 | for (key, value) in headers { 218 | builder = builder.header(key, value); 219 | } 220 | let req = builder.body(body)?; 221 | 222 | Ok(Self { inner: req }) 223 | } 224 | } 225 | ) 226 | } 227 | 228 | pub fn collections_generics_test_case2() -> Ast { 229 | parse_quote!( 230 | #[buildstructor] 231 | impl Collections { 232 | #[builder] 233 | fn new + Eq + Hash, V: Into>( 234 | map: HashMap, 235 | set: HashSet, 236 | ) -> Collections { 237 | Self { 238 | map: map.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), 239 | set: set.into_iter().map(|v| v.into()).collect(), 240 | } 241 | } 242 | } 243 | ) 244 | } 245 | 246 | pub fn self_receiver_test_case() -> Ast { 247 | parse_quote!( 248 | #[buildstructor] 249 | impl Client { 250 | #[builder(entry = "message", exit = "send")] 251 | fn call_with_no_return(self, simple: String) {} 252 | 253 | #[builder(entry = "message_ref", exit = "send")] 254 | fn call_with_no_return_ref(&self, simple: String) {} 255 | 256 | #[builder(entry = "query", exit = "call")] 257 | fn call_with_return(self, simple: String) -> bool { 258 | true 259 | } 260 | 261 | #[builder(entry = "query_ref", exit = "call")] 262 | fn call_with_return_ref(&self, simple: String) -> bool { 263 | true 264 | } 265 | } 266 | ) 267 | } 268 | 269 | pub fn doc_test_case() -> Ast { 270 | parse_quote!( 271 | #[buildstructor] 272 | impl Foo { 273 | /// Test doc 274 | #[builder] 275 | fn new(simple: usize) -> Foo { 276 | Self { simple } 277 | } 278 | } 279 | ) 280 | } 281 | 282 | pub fn reference_test_case() -> Ast { 283 | parse_quote!( 284 | #[buildstructor] 285 | impl Foo { 286 | /// Test doc 287 | #[builder] 288 | fn new(simple: &usize) -> Foo { 289 | Self { simple } 290 | } 291 | } 292 | ) 293 | } 294 | 295 | pub fn self_reference_test_case() -> Ast { 296 | parse_quote!( 297 | #[buildstructor] 298 | impl Client { 299 | #[builder(entry = "builder")] 300 | fn new(&self) {} 301 | } 302 | ) 303 | } 304 | 305 | pub fn lifetime_test_case() -> Ast { 306 | parse_quote!( 307 | #[buildstructor] 308 | impl<'a> Foo<'a> { 309 | #[builder] 310 | fn new(simple: &'a String) -> Foo<'a> { 311 | Self { simple } 312 | } 313 | } 314 | ) 315 | } 316 | 317 | pub fn specialization_test_case() -> Ast { 318 | parse_quote!( 319 | #[buildstructor] 320 | impl Foo { 321 | #[builder] 322 | fn bound_new(simple: usize) -> Foo { 323 | Self { simple } 324 | } 325 | } 326 | ) 327 | } 328 | 329 | pub fn specialization_returns_self_test_case() -> Ast { 330 | parse_quote!( 331 | #[buildstructor] 332 | impl Foo { 333 | #[builder] 334 | fn bound_new(simple: usize) -> Self { 335 | Self { simple } 336 | } 337 | } 338 | ) 339 | } 340 | 341 | pub fn associated_types_test_case() -> Ast { 342 | parse_quote!( 343 | #[buildstructor] 344 | impl Foo { 345 | #[builder] 346 | pub fn new(foo: T, bar: T::Bar) -> Foo { 347 | Foo { foo, bar } 348 | } 349 | } 350 | ) 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /src/buildstructor/parse.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use syn::parse::{Parse, ParseStream}; 3 | use syn::{parse2, ItemImpl, Result}; 4 | 5 | #[derive(Clone, Debug)] 6 | pub struct Ast { 7 | pub item: ItemImpl, 8 | } 9 | 10 | impl Parse for Ast { 11 | fn parse(input: ParseStream) -> Result { 12 | Ok(Ast { 13 | item: input.parse()?, 14 | }) 15 | } 16 | } 17 | 18 | pub fn parse(item: TokenStream) -> Result { 19 | parse2::(item) 20 | } 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | use crate::buildstructor::tests::{multi_field_test_case, single_field_test_case}; 25 | 26 | #[test] 27 | fn single_field_test_case_is_valid() { 28 | single_field_test_case(); 29 | } 30 | 31 | #[test] 32 | fn multiple_field_test_case_is_valid() { 33 | multi_field_test_case(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__associated_types.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | pub fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | pub type NewFooBuilder = __foo_new_builder::__FooBuilder< 14 | ( 15 | __foo_new_builder::__Required, 16 | __foo_new_builder::__Required, 17 | ), 18 | T, 19 | >; 20 | mod __foo_new_builder { 21 | use super::*; 22 | #[inline(always)] 23 | #[must_use] 24 | pub fn new() -> __FooBuilder< 25 | ( 26 | __foo_new_builder::__Required, 27 | __foo_new_builder::__Required, 28 | ), 29 | T, 30 | > { 31 | __FooBuilder { 32 | fields: (__required(), __required()), 33 | _phantom: core::default::Default::default(), 34 | } 35 | } 36 | pub struct __Required { 37 | _uninit: std::mem::MaybeUninit, 38 | } 39 | pub struct __Optional { 40 | lazy: Option, 41 | } 42 | pub struct __Set { 43 | value: T, 44 | } 45 | #[inline(always)] 46 | fn __set(value: T) -> __Set { 47 | __Set { value } 48 | } 49 | #[inline(always)] 50 | fn __required() -> __Required { 51 | __Required:: { 52 | _uninit: std::mem::MaybeUninit::uninit(), 53 | } 54 | } 55 | #[inline(always)] 56 | fn __optional() -> __Optional { 57 | __Optional:: { lazy: None } 58 | } 59 | impl From<__Optional> for __Set { 60 | #[inline(always)] 61 | fn from(o: __Optional) -> Self { 62 | __Set { 63 | value: o.lazy.unwrap_or_default(), 64 | } 65 | } 66 | } 67 | pub struct __FooBuilder<__P, T> { 68 | fields: __P, 69 | _phantom: core::marker::PhantomData<(T)>, 70 | } 71 | impl<__1, T: MyTrait> __FooBuilder<(__Required, __1), T> { 72 | #[inline(always)] 73 | #[must_use] 74 | pub fn foo(self, foo: T) -> __FooBuilder<(__Set, __1), T> { 75 | let foo = foo; 76 | __FooBuilder { 77 | fields: (__set(foo), self.fields.1), 78 | _phantom: core::default::Default::default(), 79 | } 80 | } 81 | } 82 | impl<__0, T: MyTrait> __FooBuilder<(__0, __Required), T> { 83 | #[inline(always)] 84 | #[must_use] 85 | pub fn bar<__T: Into>(self, bar: __T) -> __FooBuilder<(__0, __Set), T> { 86 | let bar = bar.into(); 87 | __FooBuilder { 88 | fields: (self.fields.0, __set(bar)), 89 | _phantom: core::default::Default::default(), 90 | } 91 | } 92 | } 93 | impl>, __P1: Into<__Set>> __FooBuilder<(__P0, __P1), T> { 94 | #[inline(always)] 95 | pub fn build(self) -> Foo { 96 | Foo::new(self.fields.0.into().value, self.fields.1.into().value) 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__async_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,)>; 14 | mod __foo_new_builder { 15 | use super::*; 16 | #[inline(always)] 17 | #[must_use] 18 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Required,)> { 19 | __FooBuilder { 20 | fields: (__required(),), 21 | _phantom: core::default::Default::default(), 22 | } 23 | } 24 | pub(super) struct __Required { 25 | _uninit: std::mem::MaybeUninit, 26 | } 27 | pub(super) struct __Optional { 28 | lazy: Option, 29 | } 30 | pub(super) struct __Set { 31 | value: T, 32 | } 33 | #[inline(always)] 34 | fn __set(value: T) -> __Set { 35 | __Set { value } 36 | } 37 | #[inline(always)] 38 | fn __required() -> __Required { 39 | __Required:: { 40 | _uninit: std::mem::MaybeUninit::uninit(), 41 | } 42 | } 43 | #[inline(always)] 44 | fn __optional() -> __Optional { 45 | __Optional:: { lazy: None } 46 | } 47 | impl From<__Optional> for __Set { 48 | #[inline(always)] 49 | fn from(o: __Optional) -> Self { 50 | __Set { 51 | value: o.lazy.unwrap_or_default(), 52 | } 53 | } 54 | } 55 | pub(super) struct __FooBuilder<__P> { 56 | fields: __P, 57 | _phantom: core::marker::PhantomData<()>, 58 | } 59 | impl __FooBuilder<(__Required,)> { 60 | #[inline(always)] 61 | #[must_use] 62 | pub(super) fn simple(self, simple: usize) -> __FooBuilder<(__Set,)> { 63 | let simple = simple; 64 | __FooBuilder { 65 | fields: (__set(simple),), 66 | _phantom: core::default::Default::default(), 67 | } 68 | } 69 | } 70 | impl<__P0: Into<__Set>> __FooBuilder<(__P0,)> { 71 | #[inline(always)] 72 | pub(super) async fn build(self) -> Foo { 73 | Foo::new(self.fields.0.into().value).await 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__collection_generics_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder + Eq + Hash, V: Into>() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder + Eq + Hash, V: Into> = 14 | __foo_new_builder::__FooBuilder<(__foo_new_builder::__Optional>,), K, V>; 15 | mod __foo_new_builder { 16 | use super::*; 17 | #[inline(always)] 18 | #[must_use] 19 | pub(super) fn new + Eq + Hash, V: Into>( 20 | ) -> __FooBuilder<(__foo_new_builder::__Optional>,), K, V> { 21 | __FooBuilder { 22 | fields: (__optional(),), 23 | _phantom: core::default::Default::default(), 24 | } 25 | } 26 | pub(super) struct __Required { 27 | _uninit: std::mem::MaybeUninit, 28 | } 29 | pub(super) struct __Optional { 30 | lazy: Option, 31 | } 32 | pub(super) struct __Set { 33 | value: T, 34 | } 35 | #[inline(always)] 36 | fn __set(value: T) -> __Set { 37 | __Set { value } 38 | } 39 | #[inline(always)] 40 | fn __required() -> __Required { 41 | __Required:: { 42 | _uninit: std::mem::MaybeUninit::uninit(), 43 | } 44 | } 45 | #[inline(always)] 46 | fn __optional() -> __Optional { 47 | __Optional:: { lazy: None } 48 | } 49 | impl From<__Optional> for __Set { 50 | #[inline(always)] 51 | fn from(o: __Optional) -> Self { 52 | __Set { 53 | value: o.lazy.unwrap_or_default(), 54 | } 55 | } 56 | } 57 | pub(super) struct __FooBuilder<__P, K, V> { 58 | fields: __P, 59 | _phantom: core::marker::PhantomData<(K, V)>, 60 | } 61 | impl + Eq + Hash, V: Into> 62 | __FooBuilder<(__Optional>,), K, V> 63 | { 64 | #[inline(always)] 65 | #[must_use] 66 | pub(super) fn param( 67 | mut self, 68 | param: HashMap, 69 | ) -> __FooBuilder<(__Optional>,), K, V> { 70 | self.fields 71 | .0 72 | .lazy 73 | .get_or_insert_with(|| core::default::Default::default()) 74 | .extend(param.into_iter()); 75 | self 76 | } 77 | #[inline(always)] 78 | #[must_use] 79 | pub(super) fn param_entry( 80 | mut self, 81 | key: K, 82 | value: V, 83 | ) -> __FooBuilder<(__Optional>,), K, V> { 84 | self.fields 85 | .0 86 | .lazy 87 | .get_or_insert_with(|| core::default::Default::default()) 88 | .insert(key, value); 89 | self 90 | } 91 | } 92 | impl + Eq + Hash, V: Into, __P0: Into<__Set>>> 93 | __FooBuilder<(__P0,), K, V> 94 | { 95 | #[inline(always)] 96 | pub(super) fn build(self) -> Foo { 97 | Foo::new(self.fields.0.into().value) 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__collection_generics_test2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Collections { 6 | #[must_use] 7 | fn builder + Eq + Hash, V: Into>() -> NewCollectionsBuilder { 8 | __collections_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewCollectionsBuilder + Eq + Hash, V: Into> = 14 | __collections_new_builder::__CollectionsBuilder< 15 | ( 16 | __collections_new_builder::__Optional>, 17 | __collections_new_builder::__Optional>, 18 | ), 19 | K, 20 | V, 21 | >; 22 | mod __collections_new_builder { 23 | use super::*; 24 | #[inline(always)] 25 | #[must_use] 26 | pub(super) fn new + Eq + Hash, V: Into>() -> __CollectionsBuilder< 27 | ( 28 | __collections_new_builder::__Optional>, 29 | __collections_new_builder::__Optional>, 30 | ), 31 | K, 32 | V, 33 | > { 34 | __CollectionsBuilder { 35 | fields: (__optional(), __optional()), 36 | _phantom: core::default::Default::default(), 37 | } 38 | } 39 | pub(super) struct __Required { 40 | _uninit: std::mem::MaybeUninit, 41 | } 42 | pub(super) struct __Optional { 43 | lazy: Option, 44 | } 45 | pub(super) struct __Set { 46 | value: T, 47 | } 48 | #[inline(always)] 49 | fn __set(value: T) -> __Set { 50 | __Set { value } 51 | } 52 | #[inline(always)] 53 | fn __required() -> __Required { 54 | __Required:: { 55 | _uninit: std::mem::MaybeUninit::uninit(), 56 | } 57 | } 58 | #[inline(always)] 59 | fn __optional() -> __Optional { 60 | __Optional:: { lazy: None } 61 | } 62 | impl From<__Optional> for __Set { 63 | #[inline(always)] 64 | fn from(o: __Optional) -> Self { 65 | __Set { 66 | value: o.lazy.unwrap_or_default(), 67 | } 68 | } 69 | } 70 | pub(super) struct __CollectionsBuilder<__P, K, V> { 71 | fields: __P, 72 | _phantom: core::marker::PhantomData<(K, V)>, 73 | } 74 | impl<__1, K: Into + Eq + Hash, V: Into> 75 | __CollectionsBuilder<(__Optional>, __1), K, V> 76 | { 77 | #[inline(always)] 78 | #[must_use] 79 | pub(super) fn map( 80 | mut self, 81 | map: HashMap, 82 | ) -> __CollectionsBuilder<(__Optional>, __1), K, V> { 83 | self.fields 84 | .0 85 | .lazy 86 | .get_or_insert_with(|| core::default::Default::default()) 87 | .extend(map.into_iter()); 88 | self 89 | } 90 | #[inline(always)] 91 | #[must_use] 92 | pub(super) fn map_entry( 93 | mut self, 94 | key: K, 95 | value: V, 96 | ) -> __CollectionsBuilder<(__Optional>, __1), K, V> { 97 | self.fields 98 | .0 99 | .lazy 100 | .get_or_insert_with(|| core::default::Default::default()) 101 | .insert(key, value); 102 | self 103 | } 104 | } 105 | impl<__0, K: Into + Eq + Hash, V: Into> 106 | __CollectionsBuilder<(__0, __Optional>), K, V> 107 | { 108 | #[inline(always)] 109 | #[must_use] 110 | pub(super) fn set( 111 | mut self, 112 | set: HashSet, 113 | ) -> __CollectionsBuilder<(__0, __Optional>), K, V> { 114 | self.fields 115 | .1 116 | .lazy 117 | .get_or_insert_with(|| core::default::Default::default()) 118 | .extend(set.into_iter()); 119 | self 120 | } 121 | #[inline(always)] 122 | #[must_use] 123 | pub(super) fn set_entry( 124 | mut self, 125 | value: K, 126 | ) -> __CollectionsBuilder<(__0, __Optional>), K, V> { 127 | self.fields 128 | .1 129 | .lazy 130 | .get_or_insert_with(|| core::default::Default::default()) 131 | .insert(value); 132 | self 133 | } 134 | } 135 | impl< 136 | K: Into + Eq + Hash, 137 | V: Into, 138 | __P0: Into<__Set>>, 139 | __P1: Into<__Set>>, 140 | > __CollectionsBuilder<(__P0, __P1), K, V> 141 | { 142 | #[inline(always)] 143 | pub(super) fn build(self) -> Collections { 144 | Collections::new(self.fields.0.into().value, self.fields.1.into().value) 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__collection_option_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<( 14 | __foo_new_builder::__Optional, Option>>, 15 | )>; 16 | mod __foo_new_builder { 17 | use super::*; 18 | #[inline(always)] 19 | #[must_use] 20 | pub(super) fn new( 21 | ) -> __FooBuilder<(__foo_new_builder::__Optional, Option>>,)> 22 | { 23 | __FooBuilder { 24 | fields: (__optional(),), 25 | _phantom: core::default::Default::default(), 26 | } 27 | } 28 | pub(super) struct __Required { 29 | _uninit: std::mem::MaybeUninit, 30 | } 31 | pub(super) struct __Optional { 32 | lazy: Option, 33 | } 34 | pub(super) struct __Set { 35 | value: T, 36 | } 37 | #[inline(always)] 38 | fn __set(value: T) -> __Set { 39 | __Set { value } 40 | } 41 | #[inline(always)] 42 | fn __required() -> __Required { 43 | __Required:: { 44 | _uninit: std::mem::MaybeUninit::uninit(), 45 | } 46 | } 47 | #[inline(always)] 48 | fn __optional() -> __Optional { 49 | __Optional:: { lazy: None } 50 | } 51 | impl From<__Optional> for __Set { 52 | #[inline(always)] 53 | fn from(o: __Optional) -> Self { 54 | __Set { 55 | value: o.lazy.unwrap_or_default(), 56 | } 57 | } 58 | } 59 | pub(super) struct __FooBuilder<__P> { 60 | fields: __P, 61 | _phantom: core::marker::PhantomData<()>, 62 | } 63 | impl __FooBuilder<(__Optional, Option>>,)> { 64 | #[inline(always)] 65 | #[must_use] 66 | pub(super) fn param( 67 | mut self, 68 | param: HashMap, Option>, 69 | ) -> __FooBuilder<(__Optional, Option>>,)> { 70 | self.fields 71 | .0 72 | .lazy 73 | .get_or_insert_with(|| core::default::Default::default()) 74 | .extend(param.into_iter()); 75 | self 76 | } 77 | #[inline(always)] 78 | #[must_use] 79 | pub(super) fn param_entry( 80 | mut self, 81 | key: Option, 82 | value: Option, 83 | ) -> __FooBuilder<(__Optional, Option>>,)> { 84 | self.fields 85 | .0 86 | .lazy 87 | .get_or_insert_with(|| core::default::Default::default()) 88 | .insert(key, value); 89 | self 90 | } 91 | } 92 | impl<__P0: Into<__Set, Option>>>> __FooBuilder<(__P0,)> { 93 | #[inline(always)] 94 | pub(super) fn build(self) -> Foo { 95 | Foo::new(self.fields.0.into().value) 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__collection_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<( 14 | __foo_new_builder::__Required, 15 | __foo_new_builder::__Optional>, 16 | __foo_new_builder::__Optional>, 17 | __foo_new_builder::__Optional>, 18 | __foo_new_builder::__Optional>, 19 | __foo_new_builder::__Optional>, 20 | )>; 21 | mod __foo_new_builder { 22 | use super::*; 23 | #[inline(always)] 24 | #[must_use] 25 | pub(super) fn new() -> __FooBuilder<( 26 | __foo_new_builder::__Required, 27 | __foo_new_builder::__Optional>, 28 | __foo_new_builder::__Optional>, 29 | __foo_new_builder::__Optional>, 30 | __foo_new_builder::__Optional>, 31 | __foo_new_builder::__Optional>, 32 | )> { 33 | __FooBuilder { 34 | fields: ( 35 | __required(), 36 | __optional(), 37 | __optional(), 38 | __optional(), 39 | __optional(), 40 | __optional(), 41 | ), 42 | _phantom: core::default::Default::default(), 43 | } 44 | } 45 | pub(super) struct __Required { 46 | _uninit: std::mem::MaybeUninit, 47 | } 48 | pub(super) struct __Optional { 49 | lazy: Option, 50 | } 51 | pub(super) struct __Set { 52 | value: T, 53 | } 54 | #[inline(always)] 55 | fn __set(value: T) -> __Set { 56 | __Set { value } 57 | } 58 | #[inline(always)] 59 | fn __required() -> __Required { 60 | __Required:: { 61 | _uninit: std::mem::MaybeUninit::uninit(), 62 | } 63 | } 64 | #[inline(always)] 65 | fn __optional() -> __Optional { 66 | __Optional:: { lazy: None } 67 | } 68 | impl From<__Optional> for __Set { 69 | #[inline(always)] 70 | fn from(o: __Optional) -> Self { 71 | __Set { 72 | value: o.lazy.unwrap_or_default(), 73 | } 74 | } 75 | } 76 | pub(super) struct __FooBuilder<__P> { 77 | fields: __P, 78 | _phantom: core::marker::PhantomData<()>, 79 | } 80 | impl<__1, __2, __3, __4, __5> __FooBuilder<(__Required, __1, __2, __3, __4, __5)> { 81 | #[inline(always)] 82 | #[must_use] 83 | pub(super) fn simple( 84 | self, 85 | simple: usize, 86 | ) -> __FooBuilder<(__Set, __1, __2, __3, __4, __5)> { 87 | let simple = simple; 88 | __FooBuilder { 89 | fields: ( 90 | __set(simple), 91 | self.fields.1, 92 | self.fields.2, 93 | self.fields.3, 94 | self.fields.4, 95 | self.fields.5, 96 | ), 97 | _phantom: core::default::Default::default(), 98 | } 99 | } 100 | } 101 | impl<__0, __2, __3, __4, __5> __FooBuilder<(__0, __Optional>, __2, __3, __4, __5)> { 102 | #[inline(always)] 103 | #[must_use] 104 | pub(super) fn set( 105 | mut self, 106 | set: HashSet, 107 | ) -> __FooBuilder<(__0, __Optional>, __2, __3, __4, __5)> { 108 | self.fields 109 | .1 110 | .lazy 111 | .get_or_insert_with(|| core::default::Default::default()) 112 | .extend(set.into_iter()); 113 | self 114 | } 115 | #[inline(always)] 116 | #[must_use] 117 | pub(super) fn set_entry<__T: Into>( 118 | mut self, 119 | value: __T, 120 | ) -> __FooBuilder<(__0, __Optional>, __2, __3, __4, __5)> { 121 | self.fields 122 | .1 123 | .lazy 124 | .get_or_insert_with(|| core::default::Default::default()) 125 | .insert(value.into()); 126 | self 127 | } 128 | } 129 | impl<__0, __1, __3, __4, __5> 130 | __FooBuilder<(__0, __1, __Optional>, __3, __4, __5)> 131 | { 132 | #[inline(always)] 133 | #[must_use] 134 | pub(super) fn map( 135 | mut self, 136 | map: HashMap, 137 | ) -> __FooBuilder<(__0, __1, __Optional>, __3, __4, __5)> { 138 | self.fields 139 | .2 140 | .lazy 141 | .get_or_insert_with(|| core::default::Default::default()) 142 | .extend(map.into_iter()); 143 | self 144 | } 145 | #[inline(always)] 146 | #[must_use] 147 | pub(super) fn map_entry<__K: Into, __V: Into>( 148 | mut self, 149 | key: __K, 150 | value: __V, 151 | ) -> __FooBuilder<(__0, __1, __Optional>, __3, __4, __5)> { 152 | self.fields 153 | .2 154 | .lazy 155 | .get_or_insert_with(|| core::default::Default::default()) 156 | .insert(key.into(), value.into()); 157 | self 158 | } 159 | } 160 | impl<__0, __1, __2, __4, __5> __FooBuilder<(__0, __1, __2, __Optional>, __4, __5)> { 161 | #[inline(always)] 162 | #[must_use] 163 | pub(super) fn vec( 164 | mut self, 165 | vec: Vec, 166 | ) -> __FooBuilder<(__0, __1, __2, __Optional>, __4, __5)> { 167 | self.fields 168 | .3 169 | .lazy 170 | .get_or_insert_with(|| core::default::Default::default()) 171 | .extend(vec.into_iter()); 172 | self 173 | } 174 | #[inline(always)] 175 | #[must_use] 176 | pub(super) fn vec_entry<__T: Into>( 177 | mut self, 178 | value: __T, 179 | ) -> __FooBuilder<(__0, __1, __2, __Optional>, __4, __5)> { 180 | self.fields 181 | .3 182 | .lazy 183 | .get_or_insert_with(|| core::default::Default::default()) 184 | .push(value.into()); 185 | self 186 | } 187 | } 188 | impl<__0, __1, __2, __3, __5> 189 | __FooBuilder<( 190 | __0, 191 | __1, 192 | __2, 193 | __3, 194 | __Optional>, 195 | __5, 196 | )> 197 | { 198 | #[inline(always)] 199 | #[must_use] 200 | pub(super) fn btmap( 201 | mut self, 202 | btmap: BTreeMap, 203 | ) -> __FooBuilder<( 204 | __0, 205 | __1, 206 | __2, 207 | __3, 208 | __Optional>, 209 | __5, 210 | )> { 211 | self.fields 212 | .4 213 | .lazy 214 | .get_or_insert_with(|| core::default::Default::default()) 215 | .extend(btmap.into_iter()); 216 | self 217 | } 218 | #[inline(always)] 219 | #[must_use] 220 | pub(super) fn btmap_entry<__K: Into, __V: Into>( 221 | mut self, 222 | key: __K, 223 | value: __V, 224 | ) -> __FooBuilder<( 225 | __0, 226 | __1, 227 | __2, 228 | __3, 229 | __Optional>, 230 | __5, 231 | )> { 232 | self.fields 233 | .4 234 | .lazy 235 | .get_or_insert_with(|| core::default::Default::default()) 236 | .insert(key.into(), value.into()); 237 | self 238 | } 239 | } 240 | impl<__0, __1, __2, __3, __4> 241 | __FooBuilder<(__0, __1, __2, __3, __4, __Optional>)> 242 | { 243 | #[inline(always)] 244 | #[must_use] 245 | pub(super) fn btset( 246 | mut self, 247 | btset: BTreeSet, 248 | ) -> __FooBuilder<(__0, __1, __2, __3, __4, __Optional>)> { 249 | self.fields 250 | .5 251 | .lazy 252 | .get_or_insert_with(|| core::default::Default::default()) 253 | .extend(btset.into_iter()); 254 | self 255 | } 256 | #[inline(always)] 257 | #[must_use] 258 | pub(super) fn btset_entry<__T: Into>( 259 | mut self, 260 | value: __T, 261 | ) -> __FooBuilder<(__0, __1, __2, __3, __4, __Optional>)> { 262 | self.fields 263 | .5 264 | .lazy 265 | .get_or_insert_with(|| core::default::Default::default()) 266 | .insert(value.into()); 267 | self 268 | } 269 | } 270 | impl< 271 | __P0: Into<__Set>, 272 | __P1: Into<__Set>>, 273 | __P2: Into<__Set>>, 274 | __P3: Into<__Set>>, 275 | __P4: Into<__Set>>, 276 | __P5: Into<__Set>>, 277 | > __FooBuilder<(__P0, __P1, __P2, __P3, __P4, __P5)> 278 | { 279 | #[inline(always)] 280 | pub(super) fn build(self) -> Foo { 281 | Foo::new( 282 | self.fields.0.into().value, 283 | self.fields.1.into().value, 284 | self.fields.2.into().value, 285 | self.fields.3.into().value, 286 | self.fields.4.into().value, 287 | self.fields.5.into().value, 288 | ) 289 | } 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__doc.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[doc = r" Test doc"] 7 | #[must_use] 8 | fn builder() -> NewFooBuilder { 9 | __foo_new_builder::new() 10 | } 11 | } 12 | #[doc = "Autogenerated by buildstructor"] 13 | #[allow(type_alias_bounds)] 14 | type NewFooBuilder = __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,)>; 15 | mod __foo_new_builder { 16 | use super::*; 17 | #[inline(always)] 18 | #[must_use] 19 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Required,)> { 20 | __FooBuilder { 21 | fields: (__required(),), 22 | _phantom: core::default::Default::default(), 23 | } 24 | } 25 | pub(super) struct __Required { 26 | _uninit: std::mem::MaybeUninit, 27 | } 28 | pub(super) struct __Optional { 29 | lazy: Option, 30 | } 31 | pub(super) struct __Set { 32 | value: T, 33 | } 34 | #[inline(always)] 35 | fn __set(value: T) -> __Set { 36 | __Set { value } 37 | } 38 | #[inline(always)] 39 | fn __required() -> __Required { 40 | __Required:: { 41 | _uninit: std::mem::MaybeUninit::uninit(), 42 | } 43 | } 44 | #[inline(always)] 45 | fn __optional() -> __Optional { 46 | __Optional:: { lazy: None } 47 | } 48 | impl From<__Optional> for __Set { 49 | #[inline(always)] 50 | fn from(o: __Optional) -> Self { 51 | __Set { 52 | value: o.lazy.unwrap_or_default(), 53 | } 54 | } 55 | } 56 | pub(super) struct __FooBuilder<__P> { 57 | fields: __P, 58 | _phantom: core::marker::PhantomData<()>, 59 | } 60 | impl __FooBuilder<(__Required,)> { 61 | #[inline(always)] 62 | #[must_use] 63 | pub(super) fn simple(self, simple: usize) -> __FooBuilder<(__Set,)> { 64 | let simple = simple; 65 | __FooBuilder { 66 | fields: (__set(simple),), 67 | _phantom: core::default::Default::default(), 68 | } 69 | } 70 | } 71 | impl<__P0: Into<__Set>> __FooBuilder<(__P0,)> { 72 | #[inline(always)] 73 | pub(super) fn build(self) -> Foo { 74 | Foo::new(self.fields.0.into().value) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__fallible_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,)>; 14 | mod __foo_new_builder { 15 | use super::*; 16 | #[inline(always)] 17 | #[must_use] 18 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Required,)> { 19 | __FooBuilder { 20 | fields: (__required(),), 21 | _phantom: core::default::Default::default(), 22 | } 23 | } 24 | pub(super) struct __Required { 25 | _uninit: std::mem::MaybeUninit, 26 | } 27 | pub(super) struct __Optional { 28 | lazy: Option, 29 | } 30 | pub(super) struct __Set { 31 | value: T, 32 | } 33 | #[inline(always)] 34 | fn __set(value: T) -> __Set { 35 | __Set { value } 36 | } 37 | #[inline(always)] 38 | fn __required() -> __Required { 39 | __Required:: { 40 | _uninit: std::mem::MaybeUninit::uninit(), 41 | } 42 | } 43 | #[inline(always)] 44 | fn __optional() -> __Optional { 45 | __Optional:: { lazy: None } 46 | } 47 | impl From<__Optional> for __Set { 48 | #[inline(always)] 49 | fn from(o: __Optional) -> Self { 50 | __Set { 51 | value: o.lazy.unwrap_or_default(), 52 | } 53 | } 54 | } 55 | pub(super) struct __FooBuilder<__P> { 56 | fields: __P, 57 | _phantom: core::marker::PhantomData<()>, 58 | } 59 | impl __FooBuilder<(__Required,)> { 60 | #[inline(always)] 61 | #[must_use] 62 | pub(super) fn simple(self, simple: usize) -> __FooBuilder<(__Set,)> { 63 | let simple = simple; 64 | __FooBuilder { 65 | fields: (__set(simple),), 66 | _phantom: core::default::Default::default(), 67 | } 68 | } 69 | } 70 | impl<__P0: Into<__Set>> __FooBuilder<(__P0,)> { 71 | #[inline(always)] 72 | pub(super) fn build(self) -> Result { 73 | Foo::new(self.fields.0.into().value) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__generic_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,), T>; 14 | mod __foo_new_builder { 15 | use super::*; 16 | #[inline(always)] 17 | #[must_use] 18 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Required,), T> { 19 | __FooBuilder { 20 | fields: (__required(),), 21 | _phantom: core::default::Default::default(), 22 | } 23 | } 24 | pub(super) struct __Required { 25 | _uninit: std::mem::MaybeUninit, 26 | } 27 | pub(super) struct __Optional { 28 | lazy: Option, 29 | } 30 | pub(super) struct __Set { 31 | value: T, 32 | } 33 | #[inline(always)] 34 | fn __set(value: T) -> __Set { 35 | __Set { value } 36 | } 37 | #[inline(always)] 38 | fn __required() -> __Required { 39 | __Required:: { 40 | _uninit: std::mem::MaybeUninit::uninit(), 41 | } 42 | } 43 | #[inline(always)] 44 | fn __optional() -> __Optional { 45 | __Optional:: { lazy: None } 46 | } 47 | impl From<__Optional> for __Set { 48 | #[inline(always)] 49 | fn from(o: __Optional) -> Self { 50 | __Set { 51 | value: o.lazy.unwrap_or_default(), 52 | } 53 | } 54 | } 55 | pub(super) struct __FooBuilder<__P, T> { 56 | fields: __P, 57 | _phantom: core::marker::PhantomData<(T)>, 58 | } 59 | impl __FooBuilder<(__Required,), T> { 60 | #[inline(always)] 61 | #[must_use] 62 | pub(super) fn simple(self, simple: T) -> __FooBuilder<(__Set,), T> { 63 | let simple = simple; 64 | __FooBuilder { 65 | fields: (__set(simple),), 66 | _phantom: core::default::Default::default(), 67 | } 68 | } 69 | } 70 | impl>> __FooBuilder<(__P0,), T> { 71 | #[inline(always)] 72 | pub(super) fn build(self) -> Foo { 73 | Foo::new(self.fields.0.into().value) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__into_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder>() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder> = 14 | __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,), T>; 15 | mod __foo_new_builder { 16 | use super::*; 17 | #[inline(always)] 18 | #[must_use] 19 | pub(super) fn new>() -> __FooBuilder<(__foo_new_builder::__Required,), T> { 20 | __FooBuilder { 21 | fields: (__required(),), 22 | _phantom: core::default::Default::default(), 23 | } 24 | } 25 | pub(super) struct __Required { 26 | _uninit: std::mem::MaybeUninit, 27 | } 28 | pub(super) struct __Optional { 29 | lazy: Option, 30 | } 31 | pub(super) struct __Set { 32 | value: T, 33 | } 34 | #[inline(always)] 35 | fn __set(value: T) -> __Set { 36 | __Set { value } 37 | } 38 | #[inline(always)] 39 | fn __required() -> __Required { 40 | __Required:: { 41 | _uninit: std::mem::MaybeUninit::uninit(), 42 | } 43 | } 44 | #[inline(always)] 45 | fn __optional() -> __Optional { 46 | __Optional:: { lazy: None } 47 | } 48 | impl From<__Optional> for __Set { 49 | #[inline(always)] 50 | fn from(o: __Optional) -> Self { 51 | __Set { 52 | value: o.lazy.unwrap_or_default(), 53 | } 54 | } 55 | } 56 | pub(super) struct __FooBuilder<__P, T> { 57 | fields: __P, 58 | _phantom: core::marker::PhantomData<(T)>, 59 | } 60 | impl> __FooBuilder<(__Required,), T> { 61 | #[inline(always)] 62 | #[must_use] 63 | pub(super) fn simple(self, simple: T) -> __FooBuilder<(__Set,), T> { 64 | let simple = simple; 65 | __FooBuilder { 66 | fields: (__set(simple),), 67 | _phantom: core::default::Default::default(), 68 | } 69 | } 70 | } 71 | impl, __P0: Into<__Set>> __FooBuilder<(__P0,), T> { 72 | #[inline(always)] 73 | pub(super) fn build(self) -> Foo { 74 | Foo::new(self.fields.0.into().value) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__into_where_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,), T>; 14 | mod __foo_new_builder { 15 | use super::*; 16 | #[inline(always)] 17 | #[must_use] 18 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Required,), T> { 19 | __FooBuilder { 20 | fields: (__required(),), 21 | _phantom: core::default::Default::default(), 22 | } 23 | } 24 | pub(super) struct __Required { 25 | _uninit: std::mem::MaybeUninit, 26 | } 27 | pub(super) struct __Optional { 28 | lazy: Option, 29 | } 30 | pub(super) struct __Set { 31 | value: T, 32 | } 33 | #[inline(always)] 34 | fn __set(value: T) -> __Set { 35 | __Set { value } 36 | } 37 | #[inline(always)] 38 | fn __required() -> __Required { 39 | __Required:: { 40 | _uninit: std::mem::MaybeUninit::uninit(), 41 | } 42 | } 43 | #[inline(always)] 44 | fn __optional() -> __Optional { 45 | __Optional:: { lazy: None } 46 | } 47 | impl From<__Optional> for __Set { 48 | #[inline(always)] 49 | fn from(o: __Optional) -> Self { 50 | __Set { 51 | value: o.lazy.unwrap_or_default(), 52 | } 53 | } 54 | } 55 | pub(super) struct __FooBuilder<__P, T> { 56 | fields: __P, 57 | _phantom: core::marker::PhantomData<(T)>, 58 | } 59 | impl __FooBuilder<(__Required,), T> { 60 | #[inline(always)] 61 | #[must_use] 62 | pub(super) fn simple(self, simple: T) -> __FooBuilder<(__Set,), T> { 63 | let simple = simple; 64 | __FooBuilder { 65 | fields: (__set(simple),), 66 | _phantom: core::default::Default::default(), 67 | } 68 | } 69 | } 70 | impl>> __FooBuilder<(__P0,), T> 71 | where 72 | T: Into, 73 | { 74 | #[inline(always)] 75 | pub(super) fn build(self) -> Foo { 76 | Foo::new(self.fields.0.into().value) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__lifetime.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl<'a> Foo<'a> { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder<'a> { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder<'a> = 14 | __foo_new_builder::__FooBuilder<'a, (__foo_new_builder::__Required<&'a String>,)>; 15 | mod __foo_new_builder { 16 | use super::*; 17 | #[inline(always)] 18 | #[must_use] 19 | pub(super) fn new<'a>() -> __FooBuilder<'a, (__foo_new_builder::__Required<&'a String>,)> { 20 | __FooBuilder { 21 | fields: (__required(),), 22 | _phantom: core::default::Default::default(), 23 | } 24 | } 25 | pub(super) struct __Required { 26 | _uninit: std::mem::MaybeUninit, 27 | } 28 | pub(super) struct __Optional { 29 | lazy: Option, 30 | } 31 | pub(super) struct __Set { 32 | value: T, 33 | } 34 | #[inline(always)] 35 | fn __set(value: T) -> __Set { 36 | __Set { value } 37 | } 38 | #[inline(always)] 39 | fn __required() -> __Required { 40 | __Required:: { 41 | _uninit: std::mem::MaybeUninit::uninit(), 42 | } 43 | } 44 | #[inline(always)] 45 | fn __optional() -> __Optional { 46 | __Optional:: { lazy: None } 47 | } 48 | impl From<__Optional> for __Set { 49 | #[inline(always)] 50 | fn from(o: __Optional) -> Self { 51 | __Set { 52 | value: o.lazy.unwrap_or_default(), 53 | } 54 | } 55 | } 56 | pub(super) struct __FooBuilder<'a, __P> { 57 | fields: __P, 58 | _phantom: core::marker::PhantomData<(&'a ())>, 59 | } 60 | impl<'a> __FooBuilder<'a, (__Required<&'a String>,)> { 61 | #[inline(always)] 62 | #[must_use] 63 | pub(super) fn simple(self, simple: &'a String) -> __FooBuilder<'a, (__Set<&'a String>,)> { 64 | let simple = simple; 65 | __FooBuilder { 66 | fields: (__set(simple),), 67 | _phantom: core::default::Default::default(), 68 | } 69 | } 70 | } 71 | impl<'a, __P0: Into<__Set<&'a String>>> __FooBuilder<'a, (__P0,)> { 72 | #[inline(always)] 73 | pub(super) fn build(self) -> Foo<'a> { 74 | Foo::new(self.fields.0.into().value) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__multi_field_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<( 14 | __foo_new_builder::__Required, 15 | __foo_new_builder::__Required, 16 | )>; 17 | mod __foo_new_builder { 18 | use super::*; 19 | #[inline(always)] 20 | #[must_use] 21 | pub(super) fn new() -> __FooBuilder<( 22 | __foo_new_builder::__Required, 23 | __foo_new_builder::__Required, 24 | )> { 25 | __FooBuilder { 26 | fields: (__required(), __required()), 27 | _phantom: core::default::Default::default(), 28 | } 29 | } 30 | pub(super) struct __Required { 31 | _uninit: std::mem::MaybeUninit, 32 | } 33 | pub(super) struct __Optional { 34 | lazy: Option, 35 | } 36 | pub(super) struct __Set { 37 | value: T, 38 | } 39 | #[inline(always)] 40 | fn __set(value: T) -> __Set { 41 | __Set { value } 42 | } 43 | #[inline(always)] 44 | fn __required() -> __Required { 45 | __Required:: { 46 | _uninit: std::mem::MaybeUninit::uninit(), 47 | } 48 | } 49 | #[inline(always)] 50 | fn __optional() -> __Optional { 51 | __Optional:: { lazy: None } 52 | } 53 | impl From<__Optional> for __Set { 54 | #[inline(always)] 55 | fn from(o: __Optional) -> Self { 56 | __Set { 57 | value: o.lazy.unwrap_or_default(), 58 | } 59 | } 60 | } 61 | pub(super) struct __FooBuilder<__P> { 62 | fields: __P, 63 | _phantom: core::marker::PhantomData<()>, 64 | } 65 | impl<__1> __FooBuilder<(__Required, __1)> { 66 | #[inline(always)] 67 | #[must_use] 68 | pub(super) fn simple(self, simple: usize) -> __FooBuilder<(__Set, __1)> { 69 | let simple = simple; 70 | __FooBuilder { 71 | fields: (__set(simple), self.fields.1), 72 | _phantom: core::default::Default::default(), 73 | } 74 | } 75 | } 76 | impl<__0> __FooBuilder<(__0, __Required)> { 77 | #[inline(always)] 78 | #[must_use] 79 | pub(super) fn simple2(self, simple2: usize) -> __FooBuilder<(__0, __Set)> { 80 | let simple2 = simple2; 81 | __FooBuilder { 82 | fields: (self.fields.0, __set(simple2)), 83 | _phantom: core::default::Default::default(), 84 | } 85 | } 86 | } 87 | impl<__P0: Into<__Set>, __P1: Into<__Set>> __FooBuilder<(__P0, __P1)> { 88 | #[inline(always)] 89 | pub(super) fn build(self) -> Foo { 90 | Foo::new(self.fields.0.into().value, self.fields.1.into().value) 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__multiple_generics_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Request { 6 | #[must_use] 7 | pub fn fake_builder() -> FakeNewRequestBuilder { 8 | __request_fake_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | pub type FakeNewRequestBuilder = __request_fake_new_builder::__RequestBuilder< 14 | ( 15 | __request_fake_new_builder::__Optional>, 16 | __request_fake_new_builder::__Optional>, 17 | __request_fake_new_builder::__Optional>, 18 | __request_fake_new_builder::__Required, 19 | ), 20 | T, 21 | K, 22 | V, 23 | >; 24 | mod __request_fake_new_builder { 25 | use super::*; 26 | #[inline(always)] 27 | #[must_use] 28 | pub fn new() -> __RequestBuilder< 29 | ( 30 | __request_fake_new_builder::__Optional>, 31 | __request_fake_new_builder::__Optional>, 32 | __request_fake_new_builder::__Optional>, 33 | __request_fake_new_builder::__Required, 34 | ), 35 | T, 36 | K, 37 | V, 38 | > { 39 | __RequestBuilder { 40 | fields: (__optional(), __optional(), __optional(), __required()), 41 | _phantom: core::default::Default::default(), 42 | } 43 | } 44 | pub struct __Required { 45 | _uninit: std::mem::MaybeUninit, 46 | } 47 | pub struct __Optional { 48 | lazy: Option, 49 | } 50 | pub struct __Set { 51 | value: T, 52 | } 53 | #[inline(always)] 54 | fn __set(value: T) -> __Set { 55 | __Set { value } 56 | } 57 | #[inline(always)] 58 | fn __required() -> __Required { 59 | __Required:: { 60 | _uninit: std::mem::MaybeUninit::uninit(), 61 | } 62 | } 63 | #[inline(always)] 64 | fn __optional() -> __Optional { 65 | __Optional:: { lazy: None } 66 | } 67 | impl From<__Optional> for __Set { 68 | #[inline(always)] 69 | fn from(o: __Optional) -> Self { 70 | __Set { 71 | value: o.lazy.unwrap_or_default(), 72 | } 73 | } 74 | } 75 | pub struct __RequestBuilder<__P, T, K, V> { 76 | fields: __P, 77 | _phantom: core::marker::PhantomData<(T, K, V)>, 78 | } 79 | impl<__1, __2, __3, T, K, V> __RequestBuilder<(__Optional>, __1, __2, __3), T, K, V> { 80 | #[inline(always)] 81 | #[must_use] 82 | pub fn headers( 83 | mut self, 84 | headers: Vec<(K, V)>, 85 | ) -> __RequestBuilder<(__Optional>, __1, __2, __3), T, K, V> 86 | where 87 | HeaderName: TryFrom, 88 | >::Error: Into, 89 | HeaderValue: TryFrom, 90 | >::Error: Into, 91 | { 92 | self.fields 93 | .0 94 | .lazy 95 | .get_or_insert_with(|| core::default::Default::default()) 96 | .extend(headers.into_iter()); 97 | self 98 | } 99 | #[inline(always)] 100 | #[must_use] 101 | pub fn header( 102 | mut self, 103 | value: (K, V), 104 | ) -> __RequestBuilder<(__Optional>, __1, __2, __3), T, K, V> 105 | where 106 | HeaderName: TryFrom, 107 | >::Error: Into, 108 | HeaderValue: TryFrom, 109 | >::Error: Into, 110 | { 111 | self.fields 112 | .0 113 | .lazy 114 | .get_or_insert_with(|| core::default::Default::default()) 115 | .push(value); 116 | self 117 | } 118 | } 119 | impl<__0, __2, __3, T, K, V> 120 | __RequestBuilder<(__0, __Optional>, __2, __3), T, K, V> 121 | { 122 | #[inline(always)] 123 | #[must_use] 124 | pub fn uri<__T: Into>( 125 | self, 126 | uri: __T, 127 | ) -> __RequestBuilder<(__0, __Set>, __2, __3), T, K, V> 128 | where 129 | HeaderName: TryFrom, 130 | >::Error: Into, 131 | HeaderValue: TryFrom, 132 | >::Error: Into, 133 | { 134 | let uri = Some(uri.into()); 135 | __RequestBuilder { 136 | fields: (self.fields.0, __set(uri), self.fields.2, self.fields.3), 137 | _phantom: core::default::Default::default(), 138 | } 139 | } 140 | #[inline(always)] 141 | #[must_use] 142 | pub fn and_uri<__T: Into>( 143 | self, 144 | uri: Option<__T>, 145 | ) -> __RequestBuilder<(__0, __Set>, __2, __3), T, K, V> 146 | where 147 | HeaderName: TryFrom, 148 | >::Error: Into, 149 | HeaderValue: TryFrom, 150 | >::Error: Into, 151 | { 152 | let uri = uri.map(|v| v.into()); 153 | __RequestBuilder { 154 | fields: (self.fields.0, __set(uri), self.fields.2, self.fields.3), 155 | _phantom: core::default::Default::default(), 156 | } 157 | } 158 | } 159 | impl<__0, __1, __3, T, K, V> 160 | __RequestBuilder<(__0, __1, __Optional>, __3), T, K, V> 161 | { 162 | #[inline(always)] 163 | #[must_use] 164 | pub fn method<__T: Into>( 165 | self, 166 | method: __T, 167 | ) -> __RequestBuilder<(__0, __1, __Set>, __3), T, K, V> 168 | where 169 | HeaderName: TryFrom, 170 | >::Error: Into, 171 | HeaderValue: TryFrom, 172 | >::Error: Into, 173 | { 174 | let method = Some(method.into()); 175 | __RequestBuilder { 176 | fields: (self.fields.0, self.fields.1, __set(method), self.fields.3), 177 | _phantom: core::default::Default::default(), 178 | } 179 | } 180 | #[inline(always)] 181 | #[must_use] 182 | pub fn and_method<__T: Into>( 183 | self, 184 | method: Option<__T>, 185 | ) -> __RequestBuilder<(__0, __1, __Set>, __3), T, K, V> 186 | where 187 | HeaderName: TryFrom, 188 | >::Error: Into, 189 | HeaderValue: TryFrom, 190 | >::Error: Into, 191 | { 192 | let method = method.map(|v| v.into()); 193 | __RequestBuilder { 194 | fields: (self.fields.0, self.fields.1, __set(method), self.fields.3), 195 | _phantom: core::default::Default::default(), 196 | } 197 | } 198 | } 199 | impl<__0, __1, __2, T, K, V> __RequestBuilder<(__0, __1, __2, __Required), T, K, V> { 200 | #[inline(always)] 201 | #[must_use] 202 | pub fn body(self, body: T) -> __RequestBuilder<(__0, __1, __2, __Set), T, K, V> { 203 | let body = body; 204 | __RequestBuilder { 205 | fields: (self.fields.0, self.fields.1, self.fields.2, __set(body)), 206 | _phantom: core::default::Default::default(), 207 | } 208 | } 209 | } 210 | impl< 211 | T, 212 | K, 213 | V, 214 | __P0: Into<__Set>>, 215 | __P1: Into<__Set>>, 216 | __P2: Into<__Set>>, 217 | __P3: Into<__Set>, 218 | > __RequestBuilder<(__P0, __P1, __P2, __P3), T, K, V> 219 | where 220 | HeaderName: TryFrom, 221 | >::Error: Into, 222 | HeaderValue: TryFrom, 223 | >::Error: Into, 224 | { 225 | #[inline(always)] 226 | pub fn build(self) -> http::Result> { 227 | Request::fake_new( 228 | self.fields.0.into().value, 229 | self.fields.1.into().value, 230 | self.fields.2.into().value, 231 | self.fields.3.into().value, 232 | ) 233 | } 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__option_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = 14 | __foo_new_builder::__FooBuilder<(__foo_new_builder::__Optional>,)>; 15 | mod __foo_new_builder { 16 | use super::*; 17 | #[inline(always)] 18 | #[must_use] 19 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Optional>,)> { 20 | __FooBuilder { 21 | fields: (__optional(),), 22 | _phantom: core::default::Default::default(), 23 | } 24 | } 25 | pub(super) struct __Required { 26 | _uninit: std::mem::MaybeUninit, 27 | } 28 | pub(super) struct __Optional { 29 | lazy: Option, 30 | } 31 | pub(super) struct __Set { 32 | value: T, 33 | } 34 | #[inline(always)] 35 | fn __set(value: T) -> __Set { 36 | __Set { value } 37 | } 38 | #[inline(always)] 39 | fn __required() -> __Required { 40 | __Required:: { 41 | _uninit: std::mem::MaybeUninit::uninit(), 42 | } 43 | } 44 | #[inline(always)] 45 | fn __optional() -> __Optional { 46 | __Optional:: { lazy: None } 47 | } 48 | impl From<__Optional> for __Set { 49 | #[inline(always)] 50 | fn from(o: __Optional) -> Self { 51 | __Set { 52 | value: o.lazy.unwrap_or_default(), 53 | } 54 | } 55 | } 56 | pub(super) struct __FooBuilder<__P> { 57 | fields: __P, 58 | _phantom: core::marker::PhantomData<()>, 59 | } 60 | impl __FooBuilder<(__Optional>,)> { 61 | #[inline(always)] 62 | #[must_use] 63 | pub(super) fn option(self, option: usize) -> __FooBuilder<(__Set>,)> { 64 | let option = Some(option); 65 | __FooBuilder { 66 | fields: (__set(option),), 67 | _phantom: core::default::Default::default(), 68 | } 69 | } 70 | #[inline(always)] 71 | #[must_use] 72 | pub(super) fn and_option( 73 | self, 74 | option: Option, 75 | ) -> __FooBuilder<(__Set>,)> { 76 | let option = option.map(|v| v); 77 | __FooBuilder { 78 | fields: (__set(option),), 79 | _phantom: core::default::Default::default(), 80 | } 81 | } 82 | } 83 | impl<__P0: Into<__Set>>> __FooBuilder<(__P0,)> { 84 | #[inline(always)] 85 | pub(super) fn build(self) -> Foo { 86 | Foo::new(self.fields.0.into().value) 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__pub_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | pub fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | pub type NewFooBuilder = __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,)>; 14 | mod __foo_new_builder { 15 | use super::*; 16 | #[inline(always)] 17 | #[must_use] 18 | pub fn new() -> __FooBuilder<(__foo_new_builder::__Required,)> { 19 | __FooBuilder { 20 | fields: (__required(),), 21 | _phantom: core::default::Default::default(), 22 | } 23 | } 24 | pub struct __Required { 25 | _uninit: std::mem::MaybeUninit, 26 | } 27 | pub struct __Optional { 28 | lazy: Option, 29 | } 30 | pub struct __Set { 31 | value: T, 32 | } 33 | #[inline(always)] 34 | fn __set(value: T) -> __Set { 35 | __Set { value } 36 | } 37 | #[inline(always)] 38 | fn __required() -> __Required { 39 | __Required:: { 40 | _uninit: std::mem::MaybeUninit::uninit(), 41 | } 42 | } 43 | #[inline(always)] 44 | fn __optional() -> __Optional { 45 | __Optional:: { lazy: None } 46 | } 47 | impl From<__Optional> for __Set { 48 | #[inline(always)] 49 | fn from(o: __Optional) -> Self { 50 | __Set { 51 | value: o.lazy.unwrap_or_default(), 52 | } 53 | } 54 | } 55 | pub struct __FooBuilder<__P> { 56 | fields: __P, 57 | _phantom: core::marker::PhantomData<()>, 58 | } 59 | impl __FooBuilder<(__Required,)> { 60 | #[inline(always)] 61 | #[must_use] 62 | pub fn simple(self, simple: usize) -> __FooBuilder<(__Set,)> { 63 | let simple = simple; 64 | __FooBuilder { 65 | fields: (__set(simple),), 66 | _phantom: core::default::Default::default(), 67 | } 68 | } 69 | } 70 | impl<__P0: Into<__Set>> __FooBuilder<(__P0,)> { 71 | #[inline(always)] 72 | pub fn build(self) -> Foo { 73 | Foo::new(self.fields.0.into().value) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__reference.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[doc = r" Test doc"] 7 | #[must_use] 8 | fn builder() -> NewFooBuilder { 9 | __foo_new_builder::new() 10 | } 11 | } 12 | #[doc = "Autogenerated by buildstructor"] 13 | #[allow(type_alias_bounds)] 14 | type NewFooBuilder<'__a> = 15 | __foo_new_builder::__FooBuilder<'__a, (__foo_new_builder::__Required<&usize>,)>; 16 | mod __foo_new_builder { 17 | use super::*; 18 | #[inline(always)] 19 | #[must_use] 20 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Required<&usize>,)> { 21 | __FooBuilder { 22 | fields: (__required(),), 23 | _phantom: core::default::Default::default(), 24 | } 25 | } 26 | pub(super) struct __Required { 27 | _uninit: std::mem::MaybeUninit, 28 | } 29 | pub(super) struct __Optional { 30 | lazy: Option, 31 | } 32 | pub(super) struct __Set { 33 | value: T, 34 | } 35 | #[inline(always)] 36 | fn __set(value: T) -> __Set { 37 | __Set { value } 38 | } 39 | #[inline(always)] 40 | fn __required() -> __Required { 41 | __Required:: { 42 | _uninit: std::mem::MaybeUninit::uninit(), 43 | } 44 | } 45 | #[inline(always)] 46 | fn __optional() -> __Optional { 47 | __Optional:: { lazy: None } 48 | } 49 | impl From<__Optional> for __Set { 50 | #[inline(always)] 51 | fn from(o: __Optional) -> Self { 52 | __Set { 53 | value: o.lazy.unwrap_or_default(), 54 | } 55 | } 56 | } 57 | pub(super) struct __FooBuilder<__P> { 58 | fields: __P, 59 | _phantom: core::marker::PhantomData<()>, 60 | } 61 | impl __FooBuilder<(__Required<&usize>,)> { 62 | #[inline(always)] 63 | #[must_use] 64 | pub(super) fn simple(self, simple: &usize) -> __FooBuilder<(__Set<&usize>,)> { 65 | let simple = simple; 66 | __FooBuilder { 67 | fields: (__set(simple),), 68 | _phantom: core::default::Default::default(), 69 | } 70 | } 71 | } 72 | impl<__P0: Into<__Set<&usize>>> __FooBuilder<(__P0,)> { 73 | #[inline(always)] 74 | pub(super) fn build(self) -> Foo { 75 | Foo::new(self.fields.0.into().value) 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__returns_self_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,)>; 14 | mod __foo_new_builder { 15 | use super::*; 16 | #[inline(always)] 17 | #[must_use] 18 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Required,)> { 19 | __FooBuilder { 20 | fields: (__required(),), 21 | _phantom: core::default::Default::default(), 22 | } 23 | } 24 | pub(super) struct __Required { 25 | _uninit: std::mem::MaybeUninit, 26 | } 27 | pub(super) struct __Optional { 28 | lazy: Option, 29 | } 30 | pub(super) struct __Set { 31 | value: T, 32 | } 33 | #[inline(always)] 34 | fn __set(value: T) -> __Set { 35 | __Set { value } 36 | } 37 | #[inline(always)] 38 | fn __required() -> __Required { 39 | __Required:: { 40 | _uninit: std::mem::MaybeUninit::uninit(), 41 | } 42 | } 43 | #[inline(always)] 44 | fn __optional() -> __Optional { 45 | __Optional:: { lazy: None } 46 | } 47 | impl From<__Optional> for __Set { 48 | #[inline(always)] 49 | fn from(o: __Optional) -> Self { 50 | __Set { 51 | value: o.lazy.unwrap_or_default(), 52 | } 53 | } 54 | } 55 | pub(super) struct __FooBuilder<__P> { 56 | fields: __P, 57 | _phantom: core::marker::PhantomData<()>, 58 | } 59 | impl __FooBuilder<(__Required,)> { 60 | #[inline(always)] 61 | #[must_use] 62 | pub(super) fn simple(self, simple: usize) -> __FooBuilder<(__Set,)> { 63 | let simple = simple; 64 | __FooBuilder { 65 | fields: (__set(simple),), 66 | _phantom: core::default::Default::default(), 67 | } 68 | } 69 | } 70 | impl<__P0: Into<__Set>> __FooBuilder<(__P0,)> { 71 | #[inline(always)] 72 | pub(super) fn build(self) -> Foo { 73 | Foo::new(self.fields.0.into().value) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__self_receiver-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Client { 6 | #[must_use] 7 | fn message_ref(&self) -> CallWithNoReturnRefClientBuilder { 8 | __client_call_with_no_return_ref_builder::new(self) 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type CallWithNoReturnRefClientBuilder<'__a> = 14 | __client_call_with_no_return_ref_builder::__ClientBuilder< 15 | '__a, 16 | (__client_call_with_no_return_ref_builder::__Required,), 17 | >; 18 | mod __client_call_with_no_return_ref_builder { 19 | use super::*; 20 | #[inline(always)] 21 | #[must_use] 22 | pub(super) fn new( 23 | receiver: &Client, 24 | ) -> __ClientBuilder<(__client_call_with_no_return_ref_builder::__Required,)> { 25 | __ClientBuilder { 26 | receiver, 27 | fields: (__required(),), 28 | _phantom: core::default::Default::default(), 29 | } 30 | } 31 | pub(super) struct __Required { 32 | _uninit: std::mem::MaybeUninit, 33 | } 34 | pub(super) struct __Optional { 35 | lazy: Option, 36 | } 37 | pub(super) struct __Set { 38 | value: T, 39 | } 40 | #[inline(always)] 41 | fn __set(value: T) -> __Set { 42 | __Set { value } 43 | } 44 | #[inline(always)] 45 | fn __required() -> __Required { 46 | __Required:: { 47 | _uninit: std::mem::MaybeUninit::uninit(), 48 | } 49 | } 50 | #[inline(always)] 51 | fn __optional() -> __Optional { 52 | __Optional:: { lazy: None } 53 | } 54 | impl From<__Optional> for __Set { 55 | #[inline(always)] 56 | fn from(o: __Optional) -> Self { 57 | __Set { 58 | value: o.lazy.unwrap_or_default(), 59 | } 60 | } 61 | } 62 | pub(super) struct __ClientBuilder<'__builder, __P> { 63 | receiver: &'__builder Client, 64 | fields: __P, 65 | _phantom: core::marker::PhantomData<()>, 66 | } 67 | impl<'__builder> __ClientBuilder<'__builder, (__Required,)> { 68 | #[inline(always)] 69 | #[must_use] 70 | pub(super) fn simple<__T: Into>( 71 | self, 72 | simple: __T, 73 | ) -> __ClientBuilder<'__builder, (__Set,)> { 74 | let simple = simple.into(); 75 | __ClientBuilder { 76 | receiver: self.receiver, 77 | fields: (__set(simple),), 78 | _phantom: core::default::Default::default(), 79 | } 80 | } 81 | } 82 | impl<'__builder, __P0: Into<__Set>> __ClientBuilder<'__builder, (__P0,)> { 83 | #[inline(always)] 84 | pub(super) fn send(self) { 85 | self.receiver 86 | .call_with_no_return_ref(self.fields.0.into().value) 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__self_receiver-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Client { 6 | #[must_use] 7 | fn query(self) -> CallWithReturnClientBuilder { 8 | __client_call_with_return_builder::new(self) 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type CallWithReturnClientBuilder = __client_call_with_return_builder::__ClientBuilder<( 14 | __client_call_with_return_builder::__Required, 15 | )>; 16 | mod __client_call_with_return_builder { 17 | use super::*; 18 | #[inline(always)] 19 | #[must_use] 20 | pub(super) fn new( 21 | receiver: Client, 22 | ) -> __ClientBuilder<(__client_call_with_return_builder::__Required,)> { 23 | __ClientBuilder { 24 | receiver, 25 | fields: (__required(),), 26 | _phantom: core::default::Default::default(), 27 | } 28 | } 29 | pub(super) struct __Required { 30 | _uninit: std::mem::MaybeUninit, 31 | } 32 | pub(super) struct __Optional { 33 | lazy: Option, 34 | } 35 | pub(super) struct __Set { 36 | value: T, 37 | } 38 | #[inline(always)] 39 | fn __set(value: T) -> __Set { 40 | __Set { value } 41 | } 42 | #[inline(always)] 43 | fn __required() -> __Required { 44 | __Required:: { 45 | _uninit: std::mem::MaybeUninit::uninit(), 46 | } 47 | } 48 | #[inline(always)] 49 | fn __optional() -> __Optional { 50 | __Optional:: { lazy: None } 51 | } 52 | impl From<__Optional> for __Set { 53 | #[inline(always)] 54 | fn from(o: __Optional) -> Self { 55 | __Set { 56 | value: o.lazy.unwrap_or_default(), 57 | } 58 | } 59 | } 60 | pub(super) struct __ClientBuilder<__P> { 61 | receiver: Client, 62 | fields: __P, 63 | _phantom: core::marker::PhantomData<()>, 64 | } 65 | impl __ClientBuilder<(__Required,)> { 66 | #[inline(always)] 67 | #[must_use] 68 | pub(super) fn simple<__T: Into>( 69 | self, 70 | simple: __T, 71 | ) -> __ClientBuilder<(__Set,)> { 72 | let simple = simple.into(); 73 | __ClientBuilder { 74 | receiver: self.receiver, 75 | fields: (__set(simple),), 76 | _phantom: core::default::Default::default(), 77 | } 78 | } 79 | } 80 | impl<__P0: Into<__Set>> __ClientBuilder<(__P0,)> { 81 | #[inline(always)] 82 | pub(super) fn call(self) -> bool { 83 | self.receiver.call_with_return(self.fields.0.into().value) 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__self_receiver-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Client { 6 | #[must_use] 7 | fn query_ref(&self) -> CallWithReturnRefClientBuilder { 8 | __client_call_with_return_ref_builder::new(self) 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type CallWithReturnRefClientBuilder<'__a> = __client_call_with_return_ref_builder::__ClientBuilder< 14 | '__a, 15 | (__client_call_with_return_ref_builder::__Required,), 16 | >; 17 | mod __client_call_with_return_ref_builder { 18 | use super::*; 19 | #[inline(always)] 20 | #[must_use] 21 | pub(super) fn new( 22 | receiver: &Client, 23 | ) -> __ClientBuilder<(__client_call_with_return_ref_builder::__Required,)> { 24 | __ClientBuilder { 25 | receiver, 26 | fields: (__required(),), 27 | _phantom: core::default::Default::default(), 28 | } 29 | } 30 | pub(super) struct __Required { 31 | _uninit: std::mem::MaybeUninit, 32 | } 33 | pub(super) struct __Optional { 34 | lazy: Option, 35 | } 36 | pub(super) struct __Set { 37 | value: T, 38 | } 39 | #[inline(always)] 40 | fn __set(value: T) -> __Set { 41 | __Set { value } 42 | } 43 | #[inline(always)] 44 | fn __required() -> __Required { 45 | __Required:: { 46 | _uninit: std::mem::MaybeUninit::uninit(), 47 | } 48 | } 49 | #[inline(always)] 50 | fn __optional() -> __Optional { 51 | __Optional:: { lazy: None } 52 | } 53 | impl From<__Optional> for __Set { 54 | #[inline(always)] 55 | fn from(o: __Optional) -> Self { 56 | __Set { 57 | value: o.lazy.unwrap_or_default(), 58 | } 59 | } 60 | } 61 | pub(super) struct __ClientBuilder<'__builder, __P> { 62 | receiver: &'__builder Client, 63 | fields: __P, 64 | _phantom: core::marker::PhantomData<()>, 65 | } 66 | impl<'__builder> __ClientBuilder<'__builder, (__Required,)> { 67 | #[inline(always)] 68 | #[must_use] 69 | pub(super) fn simple<__T: Into>( 70 | self, 71 | simple: __T, 72 | ) -> __ClientBuilder<'__builder, (__Set,)> { 73 | let simple = simple.into(); 74 | __ClientBuilder { 75 | receiver: self.receiver, 76 | fields: (__set(simple),), 77 | _phantom: core::default::Default::default(), 78 | } 79 | } 80 | } 81 | impl<'__builder, __P0: Into<__Set>> __ClientBuilder<'__builder, (__P0,)> { 82 | #[inline(always)] 83 | pub(super) fn call(self) -> bool { 84 | self.receiver 85 | .call_with_return_ref(self.fields.0.into().value) 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__self_receiver.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Client { 6 | #[must_use] 7 | fn message(self) -> CallWithNoReturnClientBuilder { 8 | __client_call_with_no_return_builder::new(self) 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type CallWithNoReturnClientBuilder = __client_call_with_no_return_builder::__ClientBuilder<( 14 | __client_call_with_no_return_builder::__Required, 15 | )>; 16 | mod __client_call_with_no_return_builder { 17 | use super::*; 18 | #[inline(always)] 19 | #[must_use] 20 | pub(super) fn new( 21 | receiver: Client, 22 | ) -> __ClientBuilder<(__client_call_with_no_return_builder::__Required,)> { 23 | __ClientBuilder { 24 | receiver, 25 | fields: (__required(),), 26 | _phantom: core::default::Default::default(), 27 | } 28 | } 29 | pub(super) struct __Required { 30 | _uninit: std::mem::MaybeUninit, 31 | } 32 | pub(super) struct __Optional { 33 | lazy: Option, 34 | } 35 | pub(super) struct __Set { 36 | value: T, 37 | } 38 | #[inline(always)] 39 | fn __set(value: T) -> __Set { 40 | __Set { value } 41 | } 42 | #[inline(always)] 43 | fn __required() -> __Required { 44 | __Required:: { 45 | _uninit: std::mem::MaybeUninit::uninit(), 46 | } 47 | } 48 | #[inline(always)] 49 | fn __optional() -> __Optional { 50 | __Optional:: { lazy: None } 51 | } 52 | impl From<__Optional> for __Set { 53 | #[inline(always)] 54 | fn from(o: __Optional) -> Self { 55 | __Set { 56 | value: o.lazy.unwrap_or_default(), 57 | } 58 | } 59 | } 60 | pub(super) struct __ClientBuilder<__P> { 61 | receiver: Client, 62 | fields: __P, 63 | _phantom: core::marker::PhantomData<()>, 64 | } 65 | impl __ClientBuilder<(__Required,)> { 66 | #[inline(always)] 67 | #[must_use] 68 | pub(super) fn simple<__T: Into>( 69 | self, 70 | simple: __T, 71 | ) -> __ClientBuilder<(__Set,)> { 72 | let simple = simple.into(); 73 | __ClientBuilder { 74 | receiver: self.receiver, 75 | fields: (__set(simple),), 76 | _phantom: core::default::Default::default(), 77 | } 78 | } 79 | } 80 | impl<__P0: Into<__Set>> __ClientBuilder<(__P0,)> { 81 | #[inline(always)] 82 | pub(super) fn send(self) { 83 | self.receiver 84 | .call_with_no_return(self.fields.0.into().value) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__self_reference.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Client { 6 | #[must_use] 7 | fn builder(&self) -> NewClientBuilder { 8 | __client_new_builder::new(self) 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewClientBuilder<'__a> = __client_new_builder::__ClientBuilder<'__a, ()>; 14 | mod __client_new_builder { 15 | use super::*; 16 | #[inline(always)] 17 | #[must_use] 18 | pub(super) fn new(receiver: &Client) -> __ClientBuilder<()> { 19 | __ClientBuilder { 20 | receiver, 21 | fields: (), 22 | _phantom: core::default::Default::default(), 23 | } 24 | } 25 | pub(super) struct __Required { 26 | _uninit: std::mem::MaybeUninit, 27 | } 28 | pub(super) struct __Optional { 29 | lazy: Option, 30 | } 31 | pub(super) struct __Set { 32 | value: T, 33 | } 34 | #[inline(always)] 35 | fn __set(value: T) -> __Set { 36 | __Set { value } 37 | } 38 | #[inline(always)] 39 | fn __required() -> __Required { 40 | __Required:: { 41 | _uninit: std::mem::MaybeUninit::uninit(), 42 | } 43 | } 44 | #[inline(always)] 45 | fn __optional() -> __Optional { 46 | __Optional:: { lazy: None } 47 | } 48 | impl From<__Optional> for __Set { 49 | #[inline(always)] 50 | fn from(o: __Optional) -> Self { 51 | __Set { 52 | value: o.lazy.unwrap_or_default(), 53 | } 54 | } 55 | } 56 | pub(super) struct __ClientBuilder<'__builder, __P> { 57 | receiver: &'__builder Client, 58 | fields: __P, 59 | _phantom: core::marker::PhantomData<()>, 60 | } 61 | impl<'__builder> __ClientBuilder<'__builder, ()> { 62 | #[inline(always)] 63 | pub(super) fn call(self) { 64 | self.receiver.new() 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__single_field_test.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn builder() -> NewFooBuilder { 8 | __foo_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type NewFooBuilder = __foo_new_builder::__FooBuilder<(__foo_new_builder::__Required,)>; 14 | mod __foo_new_builder { 15 | use super::*; 16 | #[inline(always)] 17 | #[must_use] 18 | pub(super) fn new() -> __FooBuilder<(__foo_new_builder::__Required,)> { 19 | __FooBuilder { 20 | fields: (__required(),), 21 | _phantom: core::default::Default::default(), 22 | } 23 | } 24 | pub(super) struct __Required { 25 | _uninit: std::mem::MaybeUninit, 26 | } 27 | pub(super) struct __Optional { 28 | lazy: Option, 29 | } 30 | pub(super) struct __Set { 31 | value: T, 32 | } 33 | #[inline(always)] 34 | fn __set(value: T) -> __Set { 35 | __Set { value } 36 | } 37 | #[inline(always)] 38 | fn __required() -> __Required { 39 | __Required:: { 40 | _uninit: std::mem::MaybeUninit::uninit(), 41 | } 42 | } 43 | #[inline(always)] 44 | fn __optional() -> __Optional { 45 | __Optional:: { lazy: None } 46 | } 47 | impl From<__Optional> for __Set { 48 | #[inline(always)] 49 | fn from(o: __Optional) -> Self { 50 | __Set { 51 | value: o.lazy.unwrap_or_default(), 52 | } 53 | } 54 | } 55 | pub(super) struct __FooBuilder<__P> { 56 | fields: __P, 57 | _phantom: core::marker::PhantomData<()>, 58 | } 59 | impl __FooBuilder<(__Required,)> { 60 | #[inline(always)] 61 | #[must_use] 62 | pub(super) fn simple(self, simple: usize) -> __FooBuilder<(__Set,)> { 63 | let simple = simple; 64 | __FooBuilder { 65 | fields: (__set(simple),), 66 | _phantom: core::default::Default::default(), 67 | } 68 | } 69 | } 70 | impl<__P0: Into<__Set>> __FooBuilder<(__P0,)> { 71 | #[inline(always)] 72 | pub(super) fn build(self) -> Foo { 73 | Foo::new(self.fields.0.into().value) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__specialization.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn bound_builder() -> BoundNewFooBuilder { 8 | __foo_bound_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type BoundNewFooBuilder = 14 | __foo_bound_new_builder::__FooBuilder<(__foo_bound_new_builder::__Required,)>; 15 | mod __foo_bound_new_builder { 16 | use super::*; 17 | #[inline(always)] 18 | #[must_use] 19 | pub(super) fn new() -> __FooBuilder<(__foo_bound_new_builder::__Required,)> { 20 | __FooBuilder { 21 | fields: (__required(),), 22 | _phantom: core::default::Default::default(), 23 | } 24 | } 25 | pub(super) struct __Required { 26 | _uninit: std::mem::MaybeUninit, 27 | } 28 | pub(super) struct __Optional { 29 | lazy: Option, 30 | } 31 | pub(super) struct __Set { 32 | value: T, 33 | } 34 | #[inline(always)] 35 | fn __set(value: T) -> __Set { 36 | __Set { value } 37 | } 38 | #[inline(always)] 39 | fn __required() -> __Required { 40 | __Required:: { 41 | _uninit: std::mem::MaybeUninit::uninit(), 42 | } 43 | } 44 | #[inline(always)] 45 | fn __optional() -> __Optional { 46 | __Optional:: { lazy: None } 47 | } 48 | impl From<__Optional> for __Set { 49 | #[inline(always)] 50 | fn from(o: __Optional) -> Self { 51 | __Set { 52 | value: o.lazy.unwrap_or_default(), 53 | } 54 | } 55 | } 56 | pub(super) struct __FooBuilder<__P> { 57 | fields: __P, 58 | _phantom: core::marker::PhantomData<()>, 59 | } 60 | impl __FooBuilder<(__Required,)> { 61 | #[inline(always)] 62 | #[must_use] 63 | pub(super) fn simple(self, simple: usize) -> __FooBuilder<(__Set,)> { 64 | let simple = simple; 65 | __FooBuilder { 66 | fields: (__set(simple),), 67 | _phantom: core::default::Default::default(), 68 | } 69 | } 70 | } 71 | impl<__P0: Into<__Set>> __FooBuilder<(__P0,)> { 72 | #[inline(always)] 73 | pub(super) fn build(self) -> Foo { 74 | Foo::bound_new(self.fields.0.into().value) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/buildstructor/snapshots/buildstructor__buildstructor__codegen__tests__specialization_self.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: src/buildstructor/codegen.rs 3 | expression: output 4 | --- 5 | impl Foo { 6 | #[must_use] 7 | fn bound_builder() -> BoundNewFooBuilder { 8 | __foo_bound_new_builder::new() 9 | } 10 | } 11 | #[doc = "Autogenerated by buildstructor"] 12 | #[allow(type_alias_bounds)] 13 | type BoundNewFooBuilder = 14 | __foo_bound_new_builder::__FooBuilder<(__foo_bound_new_builder::__Required,)>; 15 | mod __foo_bound_new_builder { 16 | use super::*; 17 | #[inline(always)] 18 | #[must_use] 19 | pub(super) fn new() -> __FooBuilder<(__foo_bound_new_builder::__Required,)> { 20 | __FooBuilder { 21 | fields: (__required(),), 22 | _phantom: core::default::Default::default(), 23 | } 24 | } 25 | pub(super) struct __Required { 26 | _uninit: std::mem::MaybeUninit, 27 | } 28 | pub(super) struct __Optional { 29 | lazy: Option, 30 | } 31 | pub(super) struct __Set { 32 | value: T, 33 | } 34 | #[inline(always)] 35 | fn __set(value: T) -> __Set { 36 | __Set { value } 37 | } 38 | #[inline(always)] 39 | fn __required() -> __Required { 40 | __Required:: { 41 | _uninit: std::mem::MaybeUninit::uninit(), 42 | } 43 | } 44 | #[inline(always)] 45 | fn __optional() -> __Optional { 46 | __Optional:: { lazy: None } 47 | } 48 | impl From<__Optional> for __Set { 49 | #[inline(always)] 50 | fn from(o: __Optional) -> Self { 51 | __Set { 52 | value: o.lazy.unwrap_or_default(), 53 | } 54 | } 55 | } 56 | pub(super) struct __FooBuilder<__P> { 57 | fields: __P, 58 | _phantom: core::marker::PhantomData<()>, 59 | } 60 | impl __FooBuilder<(__Required,)> { 61 | #[inline(always)] 62 | #[must_use] 63 | pub(super) fn simple(self, simple: usize) -> __FooBuilder<(__Set,)> { 64 | let simple = simple; 65 | __FooBuilder { 66 | fields: (__set(simple),), 67 | _phantom: core::default::Default::default(), 68 | } 69 | } 70 | } 71 | impl<__P0: Into<__Set>> __FooBuilder<(__P0,)> { 72 | #[inline(always)] 73 | pub(super) fn build(self) -> Foo { 74 | Foo::bound_new(self.fields.0.into().value) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/buildstructor/utils.rs: -------------------------------------------------------------------------------- 1 | use quote::format_ident; 2 | use syn::punctuated::Punctuated; 3 | use syn::spanned::Spanned; 4 | use syn::{ 5 | AngleBracketedGenericArguments, Constraint, Expr, ExprPath, ExprTuple, GenericArgument, 6 | GenericParam, Generics, Ident, Lifetime, Path, PathArguments, PathSegment, Token, TraitBound, 7 | TraitBoundModifier, Type, TypeParam, TypeParamBound, TypePath, TypeTuple, WhereClause, 8 | }; 9 | 10 | static SCALAR_TYPES: &[&str] = &[ 11 | "i8", "u8", "i16", "u16", "i32", "u32", "i64", "u64", "i128", "u128", "isize", "usize", "bool", 12 | ]; 13 | 14 | pub trait IdentExt { 15 | fn to_generic_param(&self, ty: Option<&Type>) -> GenericParam; 16 | fn to_path(&self) -> Path; 17 | fn to_expr_path(&self) -> ExprPath; 18 | fn to_type_path(&self) -> TypePath; 19 | } 20 | 21 | impl IdentExt for Ident { 22 | fn to_generic_param(&self, ty: Option<&Type>) -> GenericParam { 23 | GenericParam::Type(TypeParam { 24 | attrs: Default::default(), 25 | ident: self.clone(), 26 | colon_token: Default::default(), 27 | bounds: ty.map_or(Punctuated::new(), |ty| { 28 | Punctuated::from_iter(vec![TypeParamBound::Trait(TraitBound { 29 | paren_token: Default::default(), 30 | modifier: TraitBoundModifier::None, 31 | lifetimes: Default::default(), 32 | path: ty.to_path().expect("This will only every be a path type"), 33 | })]) 34 | }), 35 | eq_token: Default::default(), 36 | default: Default::default(), 37 | }) 38 | } 39 | 40 | fn to_path(&self) -> Path { 41 | Path::from(PathSegment::from(self.clone())) 42 | } 43 | 44 | fn to_expr_path(&self) -> ExprPath { 45 | ExprPath { 46 | attrs: Default::default(), 47 | qself: Default::default(), 48 | path: self.to_path(), 49 | } 50 | } 51 | 52 | fn to_type_path(&self) -> TypePath { 53 | TypePath { 54 | qself: Default::default(), 55 | path: self.to_path(), 56 | } 57 | } 58 | } 59 | 60 | pub trait GenericsExt { 61 | fn to_tuple_type(&self) -> TypeTuple; 62 | fn to_generic_args(&self) -> AngleBracketedGenericArguments; 63 | fn to_generic_bounds(&self) -> AngleBracketedGenericArguments; 64 | fn to_expr_tuple(&self, populate: impl Fn(usize, &TypeParam) -> Expr) -> ExprTuple; 65 | fn without(self, idx: usize) -> Self; 66 | fn combine(generics: Vec<&Generics>) -> Generics; 67 | } 68 | 69 | impl GenericsExt for Generics { 70 | fn to_tuple_type(&self) -> TypeTuple { 71 | TypeTuple { 72 | paren_token: Default::default(), 73 | elems: Punctuated::from_iter( 74 | self.type_params() 75 | .map(|t| Type::Path(t.ident.to_type_path())), 76 | ) 77 | .with_trailing(), 78 | } 79 | } 80 | 81 | fn to_generic_args(&self) -> AngleBracketedGenericArguments { 82 | AngleBracketedGenericArguments { 83 | colon2_token: None, 84 | lt_token: Default::default(), 85 | args: Punctuated::from_iter(self.params.iter().filter_map(|p| match p { 86 | GenericParam::Type(t) => { 87 | Some(GenericArgument::Type(Type::Path(t.ident.to_type_path()))) 88 | } 89 | GenericParam::Lifetime(l) => Some(GenericArgument::Lifetime(l.lifetime.clone())), 90 | GenericParam::Const(_) => None, 91 | })), 92 | gt_token: Default::default(), 93 | } 94 | } 95 | 96 | fn to_generic_bounds(&self) -> AngleBracketedGenericArguments { 97 | AngleBracketedGenericArguments { 98 | colon2_token: None, 99 | lt_token: Default::default(), 100 | args: Punctuated::from_iter(self.params.iter().filter_map(|p| match p { 101 | GenericParam::Type(t) => Some(GenericArgument::Constraint(Constraint { 102 | ident: t.ident.clone(), 103 | bounds: t.bounds.clone(), 104 | colon_token: Default::default(), 105 | generics: None, 106 | })), 107 | GenericParam::Lifetime(l) => Some(GenericArgument::Lifetime(l.lifetime.clone())), 108 | GenericParam::Const(_) => None, 109 | })), 110 | gt_token: Default::default(), 111 | } 112 | } 113 | 114 | fn to_expr_tuple(&self, populate: impl Fn(usize, &TypeParam) -> Expr) -> ExprTuple { 115 | ExprTuple { 116 | attrs: Default::default(), 117 | paren_token: Default::default(), 118 | elems: Punctuated::from_iter( 119 | self.type_params() 120 | .enumerate() 121 | .map(|(idx, ty)| (populate)(idx, ty)), 122 | ) 123 | .with_trailing(), 124 | } 125 | } 126 | 127 | fn without(mut self, idx: usize) -> Self { 128 | self.params = Punctuated::from_iter( 129 | self.params 130 | .into_iter() 131 | .enumerate() 132 | .filter(|(idx2, _)| *idx2 != idx) 133 | .map(|(_, p)| p), 134 | ); 135 | self 136 | } 137 | 138 | fn combine(generics: Vec<&Generics>) -> Generics { 139 | Generics { 140 | params: Punctuated::from_iter(generics.iter().flat_map(|g| g.params.clone())), 141 | where_clause: generics.iter().filter_map(|g| g.where_clause.clone()).fold( 142 | None, 143 | |a, b| match a { 144 | None => Some(b), 145 | Some(a) => Some(WhereClause { 146 | where_token: Default::default(), 147 | predicates: Punctuated::from_iter( 148 | a.predicates.iter().chain(b.predicates.iter()).cloned(), 149 | ), 150 | }), 151 | }, 152 | ), 153 | ..Default::default() 154 | } 155 | } 156 | } 157 | 158 | pub trait AngleBracketedGenericArgumentsExt { 159 | fn insert(self, idx: usize, ty: Type) -> Self; 160 | fn maybe(self) -> Option; 161 | fn with_implicit_lifetime(self, implicit_lifetime: bool) -> Self; 162 | } 163 | 164 | impl AngleBracketedGenericArgumentsExt for AngleBracketedGenericArguments { 165 | fn insert(mut self, idx: usize, ty: Type) -> Self { 166 | self.args.insert(idx, GenericArgument::Type(ty)); 167 | self 168 | } 169 | 170 | fn maybe(self) -> Option { 171 | if self.args.is_empty() { 172 | None 173 | } else { 174 | Some(self) 175 | } 176 | } 177 | 178 | fn with_implicit_lifetime(mut self, implicit_lifetime: bool) -> Self { 179 | if implicit_lifetime { 180 | self.args.insert( 181 | 0, 182 | GenericArgument::Lifetime(Lifetime::new("'__a", self.span())), 183 | ) 184 | } 185 | self 186 | } 187 | } 188 | 189 | pub trait ExprTupleExt { 190 | fn with_expr(self, idx: usize, expr: Expr) -> Self; 191 | } 192 | 193 | impl ExprTupleExt for ExprTuple { 194 | fn with_expr(mut self, idx: usize, expr: Expr) -> Self { 195 | self.elems[idx] = expr; 196 | self 197 | } 198 | } 199 | 200 | pub trait TypeTupleExt { 201 | fn with_type(self, idx: usize, ty: Type) -> Self; 202 | } 203 | 204 | impl TypeTupleExt for TypeTuple { 205 | fn with_type(mut self, idx: usize, ty: Type) -> Self { 206 | self.elems[idx] = ty; 207 | self 208 | } 209 | } 210 | 211 | pub trait TypeExt { 212 | fn raw_ident(&self) -> Option; 213 | fn generic_args(&self) -> Option<&Punctuated>; 214 | fn wrap_in_generic(&self, ident: Ident) -> Type; 215 | fn wrap_in_generic_with_module(&self, module: &Ident, ident: Ident) -> Type; 216 | fn to_path(&self) -> Option; 217 | fn parse(name: &'static str) -> Type; 218 | fn is_into_capable(&self, impl_generics: &Generics, constructor_generics: &Generics) -> bool; 219 | } 220 | 221 | impl TypeExt for Type { 222 | fn raw_ident(&self) -> Option { 223 | if let Type::Path(path) = self { 224 | if path.path.leading_colon.is_none() && path.path.segments.len() == 1 { 225 | Some(path.path.segments[0].ident.clone()) 226 | } else { 227 | None 228 | } 229 | } else { 230 | None 231 | } 232 | } 233 | 234 | fn generic_args(&self) -> Option<&Punctuated> { 235 | if let Type::Path(path) = self { 236 | if path.path.leading_colon.is_none() && path.path.segments.len() == 1 { 237 | if let PathArguments::AngleBracketed(args) = &path.path.segments[0].arguments { 238 | return Some(&args.args); 239 | } 240 | } 241 | } 242 | None 243 | } 244 | 245 | fn wrap_in_generic(&self, ident: Ident) -> Type { 246 | Type::Path(TypePath { 247 | qself: None, 248 | path: Path { 249 | leading_colon: None, 250 | segments: Punctuated::from_iter(vec![PathSegment { 251 | ident, 252 | arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { 253 | colon2_token: Default::default(), 254 | lt_token: Default::default(), 255 | args: Punctuated::from_iter(vec![GenericArgument::Type(self.clone())]), 256 | gt_token: Default::default(), 257 | }), 258 | }]), 259 | }, 260 | }) 261 | } 262 | 263 | fn wrap_in_generic_with_module(&self, module: &Ident, ident: Ident) -> Type { 264 | Type::Path(TypePath { 265 | qself: None, 266 | path: Path { 267 | leading_colon: None, 268 | segments: Punctuated::from_iter(vec![ 269 | PathSegment { 270 | ident: module.clone(), 271 | arguments: Default::default(), 272 | }, 273 | PathSegment { 274 | ident, 275 | arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { 276 | colon2_token: Default::default(), 277 | lt_token: Default::default(), 278 | args: Punctuated::from_iter(vec![GenericArgument::Type(self.clone())]), 279 | gt_token: Default::default(), 280 | }), 281 | }, 282 | ]), 283 | }, 284 | }) 285 | } 286 | 287 | fn to_path(&self) -> Option { 288 | if let Type::Path(path) = self { 289 | return Some(path.path.clone()); 290 | } 291 | None 292 | } 293 | 294 | fn parse(name: &'static str) -> Type { 295 | Type::Path(TypePath { 296 | qself: None, 297 | path: Path { 298 | leading_colon: Default::default(), 299 | segments: Punctuated::from_iter( 300 | name.split("::") 301 | .map(|s| PathSegment::from(format_ident!("{}", s))), 302 | ), 303 | }, 304 | }) 305 | } 306 | 307 | fn is_into_capable(&self, impl_generics: &Generics, constructor_generics: &Generics) -> bool { 308 | // This is super restrictive for now. No generic types. No scalars, No tuples. 309 | // The goal is to allow users to provide their own intermediate enum type or to use strings/&str. 310 | // Maybe this can be relaxed a little in future. 311 | 312 | let ident = self.raw_ident(); 313 | 314 | match self { 315 | Type::Path(_) => {} 316 | _ => return false, 317 | } 318 | 319 | // In future we could relax this as long as the type parameters are not those on the constructor method or the impl. 320 | if self.generic_args().is_some() { 321 | return false; 322 | } 323 | 324 | // Scalar types don't need to use into, they the compiler will convert. 325 | for scalar_type in SCALAR_TYPES { 326 | if ident == Some(format_ident!("{}", scalar_type)) { 327 | return false; 328 | } 329 | } 330 | // If this is a generic type we can't really use Into as the user will have to specify the type on the builder. 331 | for p in impl_generics 332 | .params 333 | .iter() 334 | .chain(constructor_generics.params.iter()) 335 | { 336 | if let GenericParam::Type(ty) = p { 337 | if Some(&ty.ident) == ident.as_ref() { 338 | return false; 339 | } 340 | } 341 | } 342 | true 343 | } 344 | } 345 | 346 | pub trait PunctuatedExt { 347 | fn with_trailing(self) -> Self; 348 | } 349 | 350 | impl PunctuatedExt for Punctuated { 351 | fn with_trailing(mut self) -> Self { 352 | if !self.is_empty() && !self.trailing_punct() { 353 | self.push_punct(P::default()) 354 | } 355 | self 356 | } 357 | } 358 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![allow(clippy::needless_doctest_main)] 3 | extern crate core; 4 | 5 | use proc_macro::TokenStream; 6 | use proc_macro2::Ident; 7 | use quote::{format_ident, ToTokens}; 8 | use syn::__private::TokenStream2; 9 | use syn::spanned::Spanned; 10 | use syn::{parse2, parse_macro_input, parse_quote, Attribute, Data, DeriveInput, ImplItem}; 11 | mod buildstructor; 12 | use crate::buildstructor::analyze; 13 | use crate::buildstructor::analyze::BuildstructorConfig; 14 | use crate::buildstructor::codegen; 15 | use crate::buildstructor::lower; 16 | use crate::buildstructor::parse; 17 | use crate::buildstructor::utils::TypeExt; 18 | use crate::parse::Ast; 19 | 20 | /// Derive a builder from a constructor! 21 | /// 22 | /// 1. Import the `buildstructor` macro. 23 | /// 2. Annotate your `impl` containing a `new` function. 24 | /// 3. Use your automatically derived builder. 25 | /// 26 | /// TLDR: Write your Rust constructors as you would normally, and get a generated builder. 27 | /// 28 | /// # Examples 29 | /// 30 | /// ```rust 31 | /// use buildstructor::buildstructor; 32 | /// 33 | /// struct MyStruct { 34 | /// sum: usize, 35 | /// } 36 | /// 37 | /// #[buildstructor] 38 | /// impl MyStruct { 39 | /// #[builder] 40 | /// fn new(a: usize, b: usize) -> MyStruct { 41 | /// Self { sum: a + b } 42 | /// } 43 | /// } 44 | /// # #[allow(clippy::needless_doctest_main)] 45 | /// # fn main() { 46 | /// let mine = MyStruct::builder().a(2).b(3).build(); 47 | /// assert_eq!(mine.sum, 5); 48 | /// # } 49 | /// ``` 50 | #[proc_macro_attribute] 51 | pub fn buildstructor(args: TokenStream, item: TokenStream) -> TokenStream { 52 | let config = parse_macro_input!(args as BuildstructorConfig); 53 | do_buildstructor(false, config, item) 54 | } 55 | 56 | #[proc_macro_attribute] 57 | #[deprecated( 58 | since = "0.2.0", 59 | note = "#[buildstructor::builder] should be migrated to #[buildstructor::buildstructor] and individual methods annotated with #[builder]" 60 | )] 61 | pub fn builder(_attr: TokenStream, item: TokenStream) -> TokenStream { 62 | do_buildstructor(true, BuildstructorConfig::default(), item) 63 | } 64 | 65 | /// Derive a builder AND a constructor! 66 | /// 67 | /// 1. Import the `Builder` macro. 68 | /// 2. Use your automatically derived builder. 69 | /// 70 | /// TLDR: Write your Rust constructors as you would normally, and get a generated builder. 71 | /// 72 | /// # Examples 73 | /// 74 | /// ```rust 75 | /// use buildstructor::Builder; 76 | /// 77 | /// #[derive(Builder)] 78 | /// struct MyStruct { 79 | /// sum: usize, 80 | /// } 81 | /// 82 | /// # #[allow(clippy::needless_doctest_main)] 83 | /// # fn main() { 84 | /// let mine = MyStruct::builder().sum(3).build(); 85 | /// assert_eq!(mine.sum, 3); 86 | /// # } 87 | /// ``` 88 | #[proc_macro_derive(Builder)] 89 | pub fn derive_builder(item: TokenStream) -> TokenStream { 90 | do_derive(item) 91 | } 92 | 93 | fn do_buildstructor( 94 | legacy_default_builders: bool, 95 | _config: BuildstructorConfig, 96 | item: TokenStream, 97 | ) -> TokenStream { 98 | match parse::parse(item.clone().into()).map_err(|e| e.into_compile_error()) { 99 | Ok(mut ast) => { 100 | // We have the AST, we can return the token stream regardless of if there was success or not as long as we sanitize it of helper attributes. 101 | let mut results: Vec = 102 | match analyze::analyze(legacy_default_builders, &ast) 103 | .map_err(|e| e.into_compile_error()) 104 | { 105 | Ok(builders) => builders 106 | .into_iter() 107 | .map(|builder| match builder { 108 | Ok(builder) => { 109 | let ir = 110 | lower::lower(builder).map_err(|e| e.into_compile_error())?; 111 | let code_gen = 112 | codegen::codegen(ir).map_err(|e| e.into_compile_error())?; 113 | Ok(code_gen) 114 | } 115 | Err(e) => Err(e.into_compile_error()), 116 | }) 117 | .map(|r: Result| match r { 118 | Ok(r) => r.into(), 119 | Err(e) => e.into(), 120 | }) 121 | .collect(), 122 | Err(e) => { 123 | vec![e.into()] 124 | } 125 | }; 126 | 127 | // Relax clippy on constructors 128 | allow_many_params(&mut ast); 129 | 130 | // Now sanitize the AST of any helper attributes. 131 | sanitize(&mut ast); 132 | 133 | // Finally output the results. 134 | let sanitized_token_stream = ast.item.to_token_stream(); 135 | results.insert(0, sanitized_token_stream.into()); 136 | TokenStream::from_iter(results) 137 | } 138 | Err(e) => { 139 | // The parse failed so emit the original token stream as some editors rely on this. 140 | TokenStream::from_iter([item, e.into()]) 141 | } 142 | } 143 | } 144 | 145 | fn allow_many_params(ast: &mut Ast) { 146 | let allow_params: Attribute = parse_quote!(#[allow(clippy::too_many_arguments)]); 147 | ast.item.items.iter_mut().for_each(|item| { 148 | if let ImplItem::Fn(m) = item { 149 | if m.attrs 150 | .iter() 151 | .any(|attr| attr.path().get_ident() == Some(&format_ident!("builder"))) 152 | { 153 | m.attrs.push(allow_params.clone()) 154 | } 155 | } 156 | }); 157 | } 158 | 159 | fn sanitize(ast: &mut Ast) { 160 | ast.item.items.iter_mut().for_each(|item| { 161 | if let ImplItem::Fn(m) = item { 162 | m.attrs 163 | .retain(|a| a.path().get_ident() != Some(&format_ident!("builder"))); 164 | } 165 | }); 166 | } 167 | 168 | pub(crate) fn do_derive(item: TokenStream) -> TokenStream { 169 | let input: DeriveInput = parse2(item.into()).unwrap(); 170 | let vis = &input.vis.to_token_stream().to_string(); 171 | let self_ty = &input.ident; 172 | let (impl_generics, ty_generics, where_clause) = &input.generics.split_for_impl(); 173 | if let Data::Struct(s) = &input.data { 174 | let parameters: Vec = s 175 | .fields 176 | .iter() 177 | .map(|f| { 178 | let name = &f.ident; 179 | let ty = &f.ty; 180 | quote::quote! { 181 | #name : #ty 182 | } 183 | }) 184 | .collect(); 185 | 186 | let fields: Vec<&Option> = s.fields.iter().map(|f| &f.ident).collect(); 187 | let arguments_doc = s 188 | .fields 189 | .iter() 190 | .map(|f| { 191 | format!( 192 | "* `{}`: {}{}", 193 | f.ident.as_ref().map(|i| i.to_string()).unwrap_or_default(), 194 | f.attrs 195 | .iter() 196 | .filter(|a| a.path().get_ident() == Some(&format_ident!("doc"))) 197 | .map(|a| { 198 | let doc = a.to_token_stream().to_string(); 199 | let trimmed = doc[doc.find('\"').unwrap_or_default() + 1 200 | ..doc.rfind('\"').unwrap_or(doc.len())] 201 | .trim() 202 | .to_string(); 203 | trimmed 204 | }) 205 | .collect::>() 206 | .join("\n"), 207 | if f.ty.raw_ident() == Some(format_ident!("Option")) { 208 | " (optional)" 209 | } else { 210 | "" 211 | } 212 | ) 213 | }) 214 | .collect::>() 215 | .join("\n"); 216 | let constructor_doc = format!( 217 | "Create a new {}\n\n # Arguments\n\n{}", 218 | input.ident, arguments_doc 219 | ); 220 | 221 | quote::quote! { 222 | #[buildstructor::buildstructor] 223 | impl #impl_generics #self_ty #ty_generics #where_clause { 224 | #[doc=#constructor_doc] 225 | #[builder(visibility=#vis)] 226 | fn new( 227 | #(#parameters),* 228 | )->#self_ty #ty_generics{ 229 | Self { 230 | #(#fields),* 231 | } 232 | } 233 | } 234 | 235 | } 236 | .into() 237 | } else { 238 | syn::Error::new(input.span(), "derive(Builder) can only be used on structs") 239 | .into_compile_error() 240 | .into() 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /tests/buildstructor/fail/duplicate.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: String) -> Foo { 10 | Self { simple } 11 | } 12 | } 13 | 14 | fn main() { 15 | let _ = Foo::builder().simple("3").simple("3").build(); 16 | } 17 | -------------------------------------------------------------------------------- /tests/buildstructor/fail/duplicate.stderr: -------------------------------------------------------------------------------- 1 | error[E0599]: no method named `simple` found for struct `__FooBuilder<(__Set,)>` in the current scope 2 | --> tests/buildstructor/fail/duplicate.rs:15:40 3 | | 4 | 6 | #[buildstructor] 5 | | ---------------- method `simple` not found for this struct 6 | ... 7 | 15 | let _ = Foo::builder().simple("3").simple("3").build(); 8 | | ^^^^^^ method not found in `__FooBuilder<(__Set,)>` 9 | | 10 | = note: the method was found for 11 | - `__FooBuilder<(__Required,)>` 12 | -------------------------------------------------------------------------------- /tests/buildstructor/fail/unknown_naming.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Exchange { 3 | location: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Exchange { 8 | #[builder] 9 | fn hmm() -> Exchange { 10 | Self { 11 | location: "Fakenham".to_string(), 12 | } 13 | } 14 | #[builder] 15 | fn do_phone_call(&self, _number: String) {} 16 | } 17 | 18 | fn main() {} 19 | -------------------------------------------------------------------------------- /tests/buildstructor/fail/unknown_naming.stderr: -------------------------------------------------------------------------------- 1 | error: #[builder(entry = "")] cannot be defaulted for 'fn hmm' and must be specified via annotation 2 | --> tests/buildstructor/fail/unknown_naming.rs:9:8 3 | | 4 | 9 | fn hmm() -> Exchange { 5 | | ^^^ 6 | 7 | error: #[builder(entry = "")] cannot be defaulted for 'fn do_phone_call' and must be specified via annotation 8 | --> tests/buildstructor/fail/unknown_naming.rs:15:8 9 | | 10 | 15 | fn do_phone_call(&self, _number: String) {} 11 | | ^^^^^^^^^^^^^ 12 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/associated_types.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub trait MyTrait { 4 | type Bar; 5 | } 6 | 7 | struct MyTraitImpl {} 8 | 9 | impl MyTrait for MyTraitImpl { 10 | type Bar = String; 11 | } 12 | 13 | #[derive(Debug)] 14 | pub struct Foo { 15 | foo: T, 16 | bar: T::Bar, 17 | } 18 | 19 | #[buildstructor] 20 | impl Foo { 21 | #[builder] 22 | pub fn new(foo: T, bar: T::Bar) -> Foo { 23 | Foo { foo, bar } 24 | } 25 | } 26 | 27 | fn main() { 28 | let _ = Foo::builder().foo(MyTraitImpl {}).bar("hi").build(); 29 | } 30 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/async.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | pub struct Foo { 4 | simple: usize, 5 | } 6 | 7 | #[buildstructor] 8 | impl Foo { 9 | #[builder] 10 | async fn new(simple: usize) -> Foo { 11 | Foo { simple } 12 | } 13 | } 14 | 15 | #[tokio::main] 16 | async fn main() { 17 | let _ = Foo::builder().simple(3).build().await; 18 | } 19 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/collections.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | use std::collections::{HashMap, HashSet}; 3 | 4 | pub struct Foo { 5 | names: HashSet, 6 | ages: HashMap, 7 | addresses: Vec, 8 | } 9 | 10 | #[buildstructor] 11 | impl Foo { 12 | #[builder] 13 | fn new(names: HashSet, ages: HashMap, addresses: Vec) -> Foo { 14 | Self { 15 | names, 16 | ages, 17 | addresses, 18 | } 19 | } 20 | } 21 | 22 | fn main() { 23 | let _ = Foo::builder() 24 | .name("Nandor".to_string()) 25 | .name("Nandor") 26 | .name("Colin".to_string()) 27 | .names(HashSet::from(["Nadja", "Laszlo"].map(str::to_string))) 28 | .age("Nandor".to_string(), 0) 29 | .age("Nandor", 759) 30 | .age("Colin".to_string(), 100) 31 | .ages(HashMap::from( 32 | [("Nadja", 650), ("Laszlo", 364)].map(|(k, v)| (k.to_string(), v)), 33 | )) 34 | .address("Staten Island".to_string()) 35 | .address("Staten Island") 36 | .addresses(Vec::from(["France", "Turkey"].map(str::to_string))) 37 | .build(); 38 | } 39 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/complex_generics.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | use http::header::HeaderName; 3 | use http::HeaderValue; 4 | use std::error::Error; 5 | #[derive(Debug)] 6 | pub struct Request { 7 | inner: http::Request, 8 | } 9 | 10 | #[buildstructor] 11 | impl Request { 12 | #[builder] 13 | pub fn fake_new( 14 | headers: Vec<(K, V)>, 15 | uri: Option, 16 | method: Option, 17 | body: T, 18 | ) -> http::Result> 19 | where 20 | HeaderName: TryFrom, 21 | >::Error: Into, 22 | HeaderValue: TryFrom, 23 | >::Error: Into, 24 | { 25 | let mut builder = http::request::Builder::new() 26 | .method(method.unwrap_or_default()) 27 | .uri(uri.unwrap_or_default()); 28 | for (key, value) in headers { 29 | builder = builder.header(key, value); 30 | } 31 | let req = builder.body(body)?; 32 | 33 | Ok(Self { inner: req }) 34 | } 35 | } 36 | 37 | fn main() -> Result<(), Box> { 38 | let _ = Request::fake_builder() 39 | .header(("a".to_string(), "b".to_string())) 40 | .header(("a".to_string(), "b".to_string())) 41 | .body("") 42 | .build() 43 | .unwrap(); 44 | 45 | Ok(()) 46 | } 47 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/crate_visibility.rs: -------------------------------------------------------------------------------- 1 | mod sub1 { 2 | pub(crate) struct Foo { 3 | simple: Bar1, 4 | } 5 | 6 | pub(crate) struct Bar1 { 7 | pub(crate) simple: usize, 8 | } 9 | 10 | #[buildstructor::buildstructor] 11 | impl Foo { 12 | #[builder] 13 | pub(crate) fn new(simple: Bar1) -> Self { 14 | Self { simple } 15 | } 16 | } 17 | } 18 | 19 | mod sub2 { 20 | pub struct Foo { 21 | simple: Bar2, 22 | } 23 | 24 | pub struct Bar2 { 25 | pub(crate) simple: usize, 26 | } 27 | 28 | #[buildstructor::buildstructor] 29 | impl Foo { 30 | #[builder] 31 | pub fn new(simple: Bar2) -> Self { 32 | Self { simple } 33 | } 34 | } 35 | } 36 | 37 | mod sub3 { 38 | struct Foo { 39 | simple: Bar3, 40 | } 41 | 42 | pub struct Bar3 { 43 | pub simple: usize, 44 | } 45 | 46 | #[buildstructor::buildstructor] 47 | impl Foo { 48 | #[builder] 49 | fn new(simple: Bar3) -> Self { 50 | Self { simple } 51 | } 52 | } 53 | 54 | pub fn foo() { 55 | let _ = Foo::builder().simple(Bar3 { simple: 3 }).build(); 56 | } 57 | } 58 | 59 | fn main() { 60 | let _ = sub1::Foo::builder() 61 | .simple(sub1::Bar1 { simple: 1 }) 62 | .build(); 63 | let _ = sub2::Foo::builder() 64 | .simple(sub2::Bar2 { simple: 2 }) 65 | .build(); 66 | sub3::foo(); 67 | } 68 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/default_builders.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Exchange { 3 | location: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Exchange { 8 | #[builder] 9 | fn new(location: String) -> Exchange { 10 | Self { location } 11 | } 12 | 13 | #[builder] 14 | fn fake_new() -> Exchange { 15 | Self { 16 | location: "Fakenham".to_string(), 17 | } 18 | } 19 | } 20 | 21 | fn main() { 22 | let _ = Exchange::builder().location("Fakenham").build(); 23 | let _ = Exchange::fake_builder().build(); 24 | } 25 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/deprecated.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::builder; 2 | pub struct Foo { 3 | simple: String, 4 | } 5 | 6 | #[builder] 7 | impl Foo { 8 | fn new(simple: String) -> Foo { 9 | Self { simple } 10 | } 11 | fn fake_new(simple: String) -> Foo { 12 | Self { simple } 13 | } 14 | } 15 | 16 | fn main() { 17 | let _ = Foo::builder().simple("3").build(); 18 | let _ = Foo::fake_builder().simple("3").build(); 19 | } 20 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/derive.rs: -------------------------------------------------------------------------------- 1 | #[derive(buildstructor::Builder)] 2 | pub struct Single { 3 | simple: usize, 4 | } 5 | 6 | #[derive(buildstructor::Builder)] 7 | pub struct Generic { 8 | simple: T, 9 | } 10 | 11 | fn main() { 12 | let _ = Single::builder().simple(2).build(); 13 | let _ = Generic::builder().simple(2).build(); 14 | } 15 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/docs.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: String, 4 | } 5 | 6 | /// Some other docs 7 | #[buildstructor] 8 | impl Foo { 9 | /// Test docs 10 | #[builder] 11 | fn new(simple: String) -> Foo { 12 | Self { simple } 13 | } 14 | } 15 | 16 | /// Some other docs 17 | #[derive(buildstructor::Builder)] 18 | pub struct Bar { 19 | /// Test docs 20 | simple: String, 21 | } 22 | 23 | fn main() { 24 | let _ = Foo::builder().simple("3").build(); 25 | let _ = Foo::builder().simple("3".to_string()).build(); 26 | } 27 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/entry_exit.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder(entry = "entry", exit = "exit")] 9 | fn new(simple: String) -> Foo { 10 | Self { simple } 11 | } 12 | } 13 | 14 | fn main() { 15 | let _ = Foo::entry().simple("3").exit(); 16 | } 17 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/fallible.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: usize, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: usize) -> Result { 10 | Ok(Self { simple }) 11 | } 12 | #[builder] 13 | fn self_new(simple: usize) -> Result { 14 | Ok(Self { simple }) 15 | } 16 | #[builder] 17 | fn deep_self_new(simple: usize) -> Result, String> { 18 | Ok(Ok(Self { simple })) 19 | } 20 | } 21 | 22 | fn main() { 23 | let _ = Foo::builder().simple(2).build().is_ok(); 24 | let _ = Foo::self_builder().simple(2).build().is_ok(); 25 | let _ = Foo::deep_self_builder().simple(2).build().is_ok(); 26 | } 27 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/generic.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: T, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: T) -> Foo { 10 | Self { simple } 11 | } 12 | 13 | #[builder] 14 | fn bound2_new(simple: T) -> Foo 15 | where 16 | T: std::fmt::Debug, 17 | { 18 | Self { simple } 19 | } 20 | } 21 | 22 | #[buildstructor] 23 | impl Foo { 24 | #[builder] 25 | fn bound1_new(simple: T) -> Foo { 26 | Self { simple } 27 | } 28 | } 29 | 30 | #[buildstructor] 31 | impl Foo { 32 | #[builder] 33 | fn bound3_new(simple: usize) -> Foo { 34 | Self { simple } 35 | } 36 | #[builder] 37 | fn bound4_new(simple: usize) -> Self { 38 | Self { simple } 39 | } 40 | } 41 | 42 | fn main() { 43 | let _ = Foo::builder().simple(3).build(); 44 | let _ = Foo::bound1_builder().simple(3).build(); 45 | let _ = Foo::bound2_builder().simple(3).build(); 46 | let _ = Foo::bound3_builder().simple(3).build(); 47 | let _ = Foo::bound4_builder().simple(3).build(); 48 | } 49 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/into.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new>(simple: T) -> Foo { 10 | Self { 11 | simple: simple.into(), 12 | } 13 | } 14 | } 15 | 16 | fn main() { 17 | let _ = Foo::builder().simple("2").build(); 18 | } 19 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/into_where.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: T) -> Foo 10 | where 11 | T: Into, 12 | { 13 | Self { 14 | simple: simple.into(), 15 | } 16 | } 17 | } 18 | 19 | fn main() { 20 | let _ = Foo::builder().simple("2").build(); 21 | } 22 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/lifetime.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo<'a> { 3 | simple: &'a String, 4 | } 5 | 6 | #[buildstructor] 7 | impl<'a> Foo<'a> { 8 | #[builder] 9 | fn new(simple: &'a String) -> Foo<'a> { 10 | Self { simple } 11 | } 12 | } 13 | 14 | fn main() { 15 | let f = "3".to_string(); 16 | let _ = Foo::builder().simple(&f).build(); 17 | } 18 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/multiple_builders.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo1 { 3 | simple: usize, 4 | } 5 | 6 | pub struct Foo2 { 7 | simple: usize, 8 | } 9 | 10 | #[buildstructor] 11 | impl Foo1 { 12 | #[builder] 13 | fn new(simple: usize) -> Foo1 { 14 | Self { simple } 15 | } 16 | } 17 | 18 | #[buildstructor] 19 | impl Foo2 { 20 | #[builder] 21 | fn new(simple: usize) -> Foo2 { 22 | Self { simple } 23 | } 24 | } 25 | 26 | fn main() { 27 | let _ = Foo1::builder().simple(3).build(); 28 | let _ = Foo2::builder().simple(3).build(); 29 | } 30 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/multiple_constructors.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: usize, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: usize) -> Result { 10 | Ok(Self { simple }) 11 | } 12 | #[builder] 13 | fn try_new(simple: usize) -> Result { 14 | Ok(Self { simple }) 15 | } 16 | #[builder] 17 | fn maybe_new(simple: usize) -> Result { 18 | Ok(Self { simple }) 19 | } 20 | } 21 | 22 | fn main() { 23 | let _ = Foo::builder().simple(2).build().is_ok(); 24 | let _ = Foo::try_builder().simple(2).build().is_ok(); 25 | let _ = Foo::maybe_builder().simple(2).build().is_ok(); 26 | } 27 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/multiple_fields.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: usize, 4 | simple2: usize, 5 | } 6 | 7 | #[buildstructor] 8 | impl Foo { 9 | #[builder] 10 | fn new(simple: usize, simple2: usize) -> Foo { 11 | Self { simple, simple2 } 12 | } 13 | } 14 | 15 | fn main() { 16 | let _ = Foo::builder().simple(2).simple2(3).build(); 17 | } 18 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/must_use.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: String) -> Foo { 10 | Self { simple } 11 | } 12 | } 13 | 14 | fn main() { 15 | Foo::builder().simple("3"); 16 | } 17 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/naming.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Exchange { 3 | location: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Exchange { 8 | #[builder] 9 | fn new(location: String) -> Exchange { 10 | Self { location } 11 | } 12 | 13 | #[builder] 14 | fn fake_new() -> Exchange { 15 | Self { 16 | location: "Fakenham".to_string(), 17 | } 18 | } 19 | #[builder(entry = "phone", exit = "call")] 20 | fn do_phone_call(&self, _number: String) {} 21 | } 22 | 23 | fn main() { 24 | let _ = Exchange::builder().location("Fakenham").build(); 25 | let exchange = Exchange::fake_builder().build(); 26 | exchange.phone().number("01328 286286").call(); 27 | } 28 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/option_field.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: Option, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: Option) -> Foo { 10 | Self { simple } 11 | } 12 | } 13 | 14 | fn main() { 15 | let _ = Foo::builder().simple("3").build(); 16 | let _ = Foo::builder().simple("3".to_string()).build(); 17 | let _ = Foo::builder().and_simple(Some("3")).build(); 18 | let _ = Foo::builder().and_simple(Some("3".to_string())).build(); 19 | let _ = Foo::builder().build(); 20 | } 21 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/returns_self.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: usize, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: usize) -> Self { 10 | Self { simple } 11 | } 12 | } 13 | 14 | fn main() { 15 | let _: Foo = Foo::builder().simple(3).build(); 16 | } 17 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/self_builder.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | 3 | #[derive(Default)] 4 | pub struct Client; 5 | 6 | #[buildstructor] 7 | impl Client { 8 | #[builder(entry = "message", exit = "send")] 9 | fn call_with_no_return(self, _simple: String) {} 10 | 11 | #[builder(entry = "message_ref", exit = "send")] 12 | fn call_with_no_return_ref(&self, _simple: String) {} 13 | 14 | #[builder(entry = "message_ref_mut", exit = "send")] 15 | fn call_with_no_return_ref_mut(&mut self, _simple: String) {} 16 | 17 | #[builder(entry = "query", exit = "call")] 18 | fn call_with_return(self, _simple: String) -> bool { 19 | true 20 | } 21 | 22 | #[builder(entry = "query_ref", exit = "call")] 23 | fn call_with_return_ref(&self, _simple: String) -> bool { 24 | true 25 | } 26 | 27 | #[builder(entry = "query_ref_mut", exit = "call")] 28 | fn call_with_return_ref_mut(&mut self, _simple: String) -> bool { 29 | true 30 | } 31 | } 32 | 33 | fn main() { 34 | Client::default().message().simple("3".to_string()).send(); 35 | Client::default().query().simple("3".to_string()).call(); 36 | 37 | let client = Client::default(); 38 | client.message_ref().simple("3".to_string()).send(); 39 | client.query_ref().simple("3".to_string()).call(); 40 | 41 | let mut client = Client::default(); 42 | client.message_ref_mut().simple("3".to_string()).send(); 43 | client.query_ref_mut().simple("3".to_string()).call(); 44 | } 45 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/single_field.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: String, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn new(simple: String) -> Foo { 10 | Self { simple } 11 | } 12 | } 13 | 14 | fn main() { 15 | let _ = Foo::builder().simple("3").build(); 16 | let _ = Foo::builder().simple("3".to_string()).build(); 17 | } 18 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/try_new.rs: -------------------------------------------------------------------------------- 1 | use buildstructor::buildstructor; 2 | pub struct Foo { 3 | simple: usize, 4 | } 5 | 6 | #[buildstructor] 7 | impl Foo { 8 | #[builder] 9 | fn try_new(simple: usize) -> Result { 10 | Ok(Self { simple }) 11 | } 12 | } 13 | 14 | fn main() { 15 | let _ = Foo::try_builder().simple(2).build().is_ok(); 16 | } 17 | -------------------------------------------------------------------------------- /tests/buildstructor/pass/visibility_override.rs: -------------------------------------------------------------------------------- 1 | mod sub1 { 2 | pub(crate) struct Foo { 3 | simple: Bar1, 4 | } 5 | 6 | pub(crate) struct Bar1 { 7 | pub(crate) simple: usize, 8 | } 9 | 10 | #[buildstructor::buildstructor] 11 | impl Foo { 12 | #[builder(visibility = "pub(crate)")] 13 | fn new(simple: Bar1) -> Self { 14 | Self { simple } 15 | } 16 | } 17 | } 18 | 19 | mod sub2 { 20 | pub struct Foo { 21 | simple: Bar2, 22 | } 23 | 24 | pub struct Bar2 { 25 | pub(crate) simple: usize, 26 | } 27 | 28 | #[buildstructor::buildstructor] 29 | impl Foo { 30 | #[builder(visibility = "pub")] 31 | fn new(simple: Bar2) -> Self { 32 | Self { simple } 33 | } 34 | } 35 | } 36 | 37 | fn main() { 38 | let _ = sub1::Foo::builder() 39 | .simple(sub1::Bar1 { simple: 1 }) 40 | .build(); 41 | let _ = sub2::Foo::builder() 42 | .simple(sub2::Bar2 { simple: 2 }) 43 | .build(); 44 | } 45 | -------------------------------------------------------------------------------- /tests/ui.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn ui() { 3 | let t = trybuild::TestCases::new(); 4 | t.compile_fail("tests/buildstructor/fail/*.rs"); 5 | t.pass("tests/buildstructor/pass/*.rs"); 6 | } 7 | --------------------------------------------------------------------------------