const_builder/
lib.rs

1//! Provides a [`ConstBuilder`] derive macro that generates a `*Builder` type
2//! that can be used to create a value with the builder pattern, even in a const
3//! context.
4//!
5//! The attributed type will gain an associated `builder` method, which can then
6//! be chained with function calls until all required fields are set, at which
7//! point you can call `build` to get the final value.
8//!
9//! Compile-time checks prevent setting the same field twice or calling `build`
10//! before all required fields are set.
11//!
12//! By default, the `*Builder` type and `*::builder` method have the same
13//! visibility as the type, and every field setter is `pub`, regardless of field
14//! visibility.
15//!
16//! The builder isn't clonable and its methods are called by-value, returning
17//! the updated builder value.
18//!
19//! The generated code is supported in `#![no_std]` crates.
20//!
21//! # Unsafety
22//!
23//! This derive macro generates `unsafe` code using
24//! [`MaybeUninit`](std::mem::MaybeUninit) to facilitate field-wise
25//! initialization of a struct, tracking initialized fields via const-generics.
26//! This broadly follows the guidance in the [nomicon section on unchecked
27//! uninitialized memory], and is, for now, required to get const-compatible
28//! builders for arbitrary types.
29//!
30//! # Struct Requirements
31//!
32//! All struct fields must be [`Sized`]. Fields using generic parameters may be
33//! [`?Sized`](Sized) for some parameters, as long as the actual instantiation
34//! of the builder only has [`Sized`] fields.
35//!
36//! When the struct is `#[repr(packed)]` and the last field may be
37//! [`?Sized`](Sized), the field needs to be attributed with
38//! `#[builder(unsized_tail)]` to replace the field drop code with an assert
39//! that the field cannot be dropped. Rust functionally currently requires this
40//! combination of packed and unsized tails to be
41//! [`ManuallyDrop`](std::mem::ManuallyDrop) or a wrapper around it.
42//!
43//! `enum` and `union` types are unsupported.
44//!
45//! # Default Values
46//!
47//! Fields can be attributed with `#[builder(default = None)]` or similar to
48//! be made optional by providing a default value.
49//!
50//! This default value will _not_ be dropped if it is overridden or the builder
51//! is dropped. Consequently, the value should be something that does not need
52//! to be dropped, such as a primitive, [`None`], [`String::new()`],
53//! [`Vec::new()`], [`Cow::Borrowed`](std::borrow::Cow), or similar.
54//!
55//! # API Stability
56//!
57//! The API of the emitted builder is considered forward-compatible as long as
58//! no fields are removed (even when private but not if its setter was already
59//! private) unless care is taken to ensure the surface area to consumers stays
60//! the same, and the changes don't already constitute as breaking to consumers
61//! of the original struct.
62//!
63//! Adding the `default` attribute to the struct or field is forward-compatible.
64//! Removing the attribute is a breaking change.
65//!
66//! Additionally, changes to builder attributes that lead to reduction in
67//! visibility, renames, removal, or changes in signature of functions in the
68//! emitted code are also breaking changes. This includes attributes such `vis`,
69//! `rename`, `rename_fn`, and `setter`.
70//!
71//! Major versions of this crate may also introduce breaking changes to the
72//! emitted structs. Minor versions will ensure to emit forward-compatible code.
73//!
74//! # Unchecked Builder
75//!
76//! There is also an `*UncheckedBuilder` without safety checks, which is private
77//! by default. While similar the checked builder at a glance, not every
78//! attribute applies to it in the same way (f.e. the `setter` attribute has no
79//! effect), and its API isn't considered stable across source struct
80//! modifications, so it should not be exposed in stable public interfaces.
81//!
82//! This struct is used to simplify the implementation of the checked builder
83//! and it is exposed for users that want additional control.
84//!
85//! This builder works broadly in the same way as the checked builder, however:
86//!
87//! - initialized fields aren't tracked,
88//! - setting fields that were already set will forget the old value,
89//! - calling `build` is unsafe due to the lack of tracking, and
90//! - dropping it will forget all field values that were already set.
91//!
92//! You can convert between the checked and unchecked builder with
93//! `*Builder::into_unchecked` and `*UncheckedBuilder::assert_init`.
94//!
95//! # Example
96//!
97//! ```
98//! use const_builder::ConstBuilder;
99//!
100//! #[derive(ConstBuilder)]
101//! # #[derive(Debug, PartialEq)]
102//! pub struct Person<'a> {
103//!     // fields are required by default
104//!     pub name: &'a str,
105//!     // optional fields have a default specified
106//!     // the value is required even when the type implements `Default`!
107//!     #[builder(default = 0)]
108//!     pub age: u32,
109//! }
110//!
111//! let steve = const {
112//!     Person::builder()
113//!         .name("steve smith")
114//!         .build()
115//! };
116//! # assert_eq!(
117//! #     steve,
118//! #     Person {
119//! #         name: "steve smith",
120//! #         age: 0,
121//! #     }
122//! # );
123//! ```
124//!
125//! # Generated Interface
126//!
127//! The example above would generate an interface similar to the following. The
128//! actual generated code is more complex because it includes bounds to ensure
129//! fields are only written once and that the struct is fully initialized when
130//! calling `build`.
131//!
132//! ```
133//! # // This isn't an example to run, just an example "shape".
134//! # _ = stringify!(
135//! /// A builder type for [`Person`].
136//! pub struct PersonBuilder<'a, const _NAME: bool = false, const _AGE: bool = false> { ... }
137//!
138//! impl<'a, ...> PersonBuilder<'a, ...> {
139//!     /// Creates a new builder.
140//!     pub const fn new() -> Self;
141//!
142//!     /// Returns the finished value.
143//!     ///
144//!     /// This function can only be called when all required fields have been set.
145//!     pub const fn build(self) -> Person<'a>;
146//!
147//!     // one setter function per field
148//!     pub const fn name(self, value: &'a str) -> PersonBuilder<'a, ...>;
149//!     pub const fn age(self, value: u32) -> PersonBuilder<'a, ...>;
150//!
151//!     /// Unwraps this builder into its unsafe counterpart.
152//!     ///
153//!     /// This isn't unsafe in itself, however using it carelessly may lead to
154//!     /// leaking objects and not dropping initialized values.
155//!     const fn into_unchecked(self) -> PersonUncheckedBuilder<'a>;
156//! }
157//!
158//! impl<'a> Person<'a> {
159//!     /// Creates a new builder for this type.
160//!     pub const fn builder() -> PersonBuilder<'a>;
161//! }
162//!
163//! /// An _unchecked_ builder type for [`Person`].
164//! ///
165//! /// This version being _unchecked_ means it has less safety guarantees:
166//! /// - No tracking is done whether fields are initialized, so [`Self::build`] is `unsafe`.
167//! /// - If dropped, already initialized fields will be leaked.
168//! /// - The same field can be set multiple times. If done, the old value will be leaked.
169//! struct PersonUncheckedBuilder<'a> { ... }
170//!
171//! impl<'a> PersonUncheckedBuilder<'a> {
172//!    /// Creates a new unchecked builder.
173//!    pub const fn new() -> Self;
174//!
175//!    /// Asserts that the fields specified by the const generics as well as all optional
176//!    /// fields are initialized and promotes this value into a checked builder.
177//!    ///
178//!    /// # Safety
179//!    ///
180//!    /// The fields whose const generic are `true` and all optional fields have to be
181//!    /// initialized.
182//!    ///
183//!    /// Optional fields are initialized by [`Self::new`] by default, however using
184//!    /// [`Self::as_uninit`] allows de-initializing them. This means that this function
185//!    /// isn't even necessarily safe to call if all const generics are `false`.
186//!    pub const unsafe fn assert_init<const _NAME: bool, const _AGE: bool>(self) -> PersonBuilder<'a, _NAME, _AGE>;
187//!
188//!    /// Returns the finished value.
189//!    ///
190//!    /// # Safety
191//!    ///
192//!    /// This function requires that all fields have been initialized.
193//!    pub const unsafe fn build(self) -> Person<'a>;
194//!
195//!    // one setter function per field
196//!    pub const fn name(mut self, value: &'a str) -> PersonUncheckedBuilder<'a>;
197//!    pub const fn age(mut self, value: u32) -> PersonUncheckedBuilder<'a>;
198//!
199//!    /// Gets a mutable reference to the partially initialized data.
200//!    pub const fn as_uninit(&mut self) -> &mut ::core::mem::MaybeUninit<Person<'a>>;
201//! }
202//! # );
203//! ```
204//!
205//! # Struct Attributes
206//!
207//! These attributes can be specified within `#[builder(...)]` on the struct
208//! level.
209//!
210//! | Attribute           | Meaning |
211//! |:------------------- |:------- |
212//! | `default`           | Generate a const-compatible `*::default()` function and [`Default`] derive. Requires every field to have a default value. |
213//! | `vis`               | Change the visibility of the builder type. May be an empty string for private. Default is the same as the struct. |
214//! | `rename`            | Renames the builder type. Defaults to `"<Type>Builder"`. |
215//! | `rename_fn`         | Renames the associated function that creates the builder. Defaults to `builder`. Set to `false` to disable. |
216//! | `unchecked(vis)`    | Change the visibility of the unchecked builder type. Default is private. |
217//! | `unchecked(rename)` | Renames the unchecked builder type. Defaults to `"<Type>UncheckedBuilder"`. |
218//!
219//! # Field Attributes
220//!
221//! These attributes can be specified within `#[builder(...)]` on the struct's
222//! fields.
223//!
224//! | Attribute              | Meaning |
225//! |:---------------------- |:------- |
226//! | `vis`                  | Change the visibility of the builder's field setter. May be an empty string for private. Default is `pub`. |
227//! | `default`              | Make the field optional by providing a default value. |
228//! | `rename`               | Renames the setters for this field. Defaults to the field name. |
229//! | `rename_generic`       | Renames the name of the associated const generic. Defaults to `_{field:upper}`. |
230//! | `leak_on_drop`         | Instead of dropping the field when dropping the builder, do nothing. |
231//! | `unsized_tail`         | In a packed struct, marks the last field as potentially being unsized, replacing the drop code with an assert. No effect if the struct isn't packed. |
232//! | `setter(transform)`    | Accepts closure syntax. The setter is changed to accept its inputs and set the corresponding value to its output. |
233//! | `setter(strip_option)` | On an [`Option<T>`] field, change the setter to accept `T` and wrap it in [`Some`] itself. Equivalent to `setter(transform = \|value: T\| Some(value))`. |
234//!
235//! # Attributes Example
236//!
237//! ```
238//! use const_builder::ConstBuilder;
239//!
240//! #[derive(ConstBuilder)]
241//! // change the builder from pub (same as Person) to crate-internal
242//! // also override the name of the builder to `CreatePerson`
243//! #[builder(vis = "pub(crate)", rename = "CreatePerson")]
244//! // change the unchecked builder from priv also to crate-internal
245//! #[builder(unchecked(vis = "pub(crate)"))]
246//! # #[derive(Debug, PartialEq)]
247//! pub struct Person<'a> {
248//!     // required field with public setter
249//!     name: &'a str,
250//!     // optional field with public setter
251//!     #[builder(default = 0)]
252//!     age: u32,
253//!     // optional field with private setter
254//!     #[builder(default = 1, vis = "" /* priv */)]
255//!     version: u32,
256//! }
257//!
258//! # assert_eq!(
259//! #     const {
260//! #         Person::builder()
261//! #             .name("smith")
262//! #             .build()
263//! #     },
264//! #     Person {
265//! #         name: "smith",
266//! #         age: 0,
267//! #         version: 1,
268//! #     }
269//! # );
270//! ```
271//!
272//! [nomicon section on unchecked uninitialized memory]: https://doc.rust-lang.org/nomicon/unchecked-uninit.html
273
274#![forbid(unsafe_code)]
275#![warn(clippy::doc_markdown)]
276
277use proc_macro::TokenStream;
278use syn::{DeriveInput, parse_macro_input};
279
280mod const_builder_impl;
281mod model;
282mod util;
283
284/// Generates the builder types for the attributed struct.
285///
286/// See the crate-level documentation for more details.
287#[proc_macro_derive(ConstBuilder, attributes(builder))]
288pub fn derive_const_builder(input: TokenStream) -> TokenStream {
289    let input = parse_macro_input!(input as DeriveInput);
290    const_builder_impl::entry_point(input)
291        .unwrap_or_else(|e| e.write_errors())
292        .into()
293}
294
295/// I considered UI tests but since we still emit the code on almost all errors,
296/// there are a bunch of rustc diagnostics mixed in (when the compile error
297/// isn't literally just a rustc error). These aren't stable, so those tests
298/// would just break between language versions -- or even just stable and
299/// nightly.
300///
301/// ```compile_fail
302/// #[derive(const_builder::ConstBuilder)]
303/// struct TupleStruct(u32, u64);
304/// ```
305///
306/// ```compile_fail
307/// #[derive(const_builder::ConstBuilder)]
308/// struct UnitStruct;
309/// ```
310///
311/// ```compile_fail
312/// #[derive(const_builder::ConstBuilder)]
313/// enum Enum {
314///     B { a: u32, b: u64 },
315/// }
316/// ```
317///
318/// ```compile_fail
319/// #[derive(const_builder::ConstBuilder)]
320/// union Union {
321///     a: u32,
322///     b: u64,
323/// }
324/// ```
325///
326/// ```compile_fail
327/// #[derive(const_builder::ConstBuilder)]
328/// #[builder(default)]
329/// struct InvalidDefault {
330///     a: u32,
331///     #[builder(default = 0)]
332///     b: u32,
333/// }
334/// ```
335///
336/// ```compile_fail
337/// #[derive(const_builder::ConstBuilder)]
338/// struct DefaultNoValue {
339///     #[builder(default)]
340///     a: u32,
341/// }
342/// ```
343///
344/// ```compile_fail
345/// #[derive(const_builder::ConstBuilder)]
346/// struct WrongUnsizedTailPosition {
347///     #[builder(unsized_tail)]
348///     a: u32,
349///     b: u32,
350/// }
351/// ```
352///
353/// ```compile_fail
354/// // on stable, the macro code will not compile due to `UnsizedField: Sized`
355/// // bounds. however on nightly with `trivial_bounds`, the actual output of
356/// // the macro will compile, but the bounds will still prevent instantiating
357/// // or otherwise using the builder.
358/// // see also: https://github.com/rust-lang/rust/issues/48214
359/// #[derive(const_builder::ConstBuilder)]
360/// struct UnsizedField {
361///     a: [u32],
362/// }
363///
364/// // ensure instantiating fails anyways
365/// _ = UnsizedFieldBuilder::new();
366/// ```
367///
368/// ```compile_fail
369/// // this test actually fails for two reasons:
370/// // - rust disallowing possible-Drop unsized tails in packed structs
371/// // - static assert when a packed struct's `unsized_tail` field `needs_drop`
372/// #[derive(const_builder::ConstBuilder)]
373/// #[repr(Rust, packed)]
374/// struct PackedUnsizedDropTail<T: ?Sized> {
375///     #[builder(unsized_tail)]
376///     a: T,
377/// }
378///
379/// // ensure a variant with a `needs_drop` tail is instantiated
380/// _ = PackedUnsizedDropTail::<String>::builder();
381/// ```
382///
383/// ```compile_fail
384/// #[derive(const_builder::ConstBuilder)]
385/// struct SetterCastNoClosure {
386///     #[builder(setter(transform))]
387///     value: Option<u32>,
388/// }
389/// ```
390///
391/// ```compile_fail
392/// #[derive(const_builder::ConstBuilder)]
393/// struct SetterCastNotAClosure1 {
394///     #[builder(setter(transform = r#""hello""#))]
395///     value: Option<u32>,
396/// }
397/// ```
398///
399/// ```compile_fail
400/// #[derive(const_builder::ConstBuilder)]
401/// struct SetterCastNotAClosure2 {
402///     #[builder(setter(transform = 42))]
403///     value: Option<u32>,
404/// }
405/// ```
406///
407/// ```compile_fail
408/// #[derive(const_builder::ConstBuilder)]
409/// struct SetterCastNotAClosure3 {
410///     #[builder(setter(transform = Some(42)))]
411///     value: Option<u32>,
412/// }
413/// ```
414///
415/// ```compile_fail
416/// #[derive(const_builder::ConstBuilder)]
417/// struct SetterCastNoType {
418///     #[builder(setter(transform = |i| Some(i)))]
419///     value: Option<u32>,
420/// }
421/// ```
422///
423/// ```compile_fail
424/// #[derive(const_builder::ConstBuilder)]
425/// struct SetterCastNoTypePartial1 {
426///     #[builder(setter(transform = |a: u32, b| a + b))]
427///     value: u32,
428/// }
429/// ```
430///
431/// ```compile_fail
432/// #[derive(const_builder::ConstBuilder)]
433/// struct SetterCastNoTypePartial2 {
434///     #[builder(setter(transform = |a, b: u32| a + b))]
435///     value: u32,
436/// }
437/// ```
438///
439/// ```compile_fail
440/// // `works.rs` contains a similar case that compiles
441/// #[derive(ConstBuilder)]
442/// struct SetterCastPatNoType {
443///     #[builder(setter(transform = |Wrap(v)| v))]
444///     value: u32,
445/// }
446///
447/// struct Wrap<T>(T);
448/// ```
449///
450/// ```compile_fail
451/// #[derive(const_builder::ConstBuilder)]
452/// struct SetterCastAttrs {
453///     #[builder(setter(transform = (#[inline] |i: u32| Some(i))))]
454///     value: Option<u32>,
455/// }
456/// ```
457///
458/// ```compile_fail
459/// #[derive(const_builder::ConstBuilder)]
460/// struct SetterCastWrongLifetimes {
461///     #[builder(setter(transform = for<'b> |i: &'a u32| Some(*i)))]
462///     value: Option<u32>,
463/// }
464/// ```
465///
466/// ```compile_fail
467/// #[derive(const_builder::ConstBuilder)]
468/// struct SetterCastConst {
469///     #[builder(setter(transform = const |i: u32| Some(i)))]
470///     value: Option<u32>,
471/// }
472/// ```
473///
474/// ```compile_fail
475/// #[derive(const_builder::ConstBuilder)]
476/// struct SetterCastStatic {
477///     #[builder(setter(transform = static |i: u32| Some(i)))]
478///     value: Option<u32>,
479/// }
480/// ```
481///
482/// ```compile_fail
483/// #[derive(const_builder::ConstBuilder)]
484/// struct SetterCastAsync {
485///     #[builder(setter(transform = async |i: u32| Some(i)))]
486///     value: Option<u32>,
487/// }
488/// ```
489///
490/// ```compile_fail
491/// #[derive(const_builder::ConstBuilder)]
492/// struct SetterCastMove {
493///     #[builder(setter(transform = move |i: u32| Some(i)))]
494///     value: Option<u32>,
495/// }
496/// ```
497///
498/// ```compile_fail
499/// #[derive(const_builder::ConstBuilder)]
500/// struct SetterCastReturnType {
501///     #[builder(setter(transform = |i: u32| -> Option<u32> { Some(i) }))]
502///     value: Option<u32>,
503/// }
504/// ```
505///
506/// ```compile_fail
507/// #[derive(const_builder::ConstBuilder)]
508/// struct SetterCastAndStrip {
509///     #[builder(setter(strip_option, transform = |i: u32| Some(i)))]
510///     value: Option<u32>,
511/// }
512/// ```
513///
514/// ```compile_fail
515/// #[derive(const_builder::ConstBuilder)]
516/// struct SetterCastWrongType {
517///     #[builder(setter(transform = |v: u32| v))]
518///     value: i32,
519/// }
520/// ```
521///
522/// ```compile_fail
523/// #[derive(const_builder::ConstBuilder)]
524/// struct SetterUnknown {
525///     #[builder(setter(strip_result))]
526///     value: Result<u32, u32>,
527/// }
528/// ```
529///
530/// ```compile_fail
531/// #[derive(const_builder::ConstBuilder)]
532/// struct SetterStripOptionNotOption {
533///     #[builder(setter(strip_option))]
534///     value: Result<(), ()>,
535/// }
536/// ```
537///
538/// ```compile_fail
539/// #[derive(const_builder::ConstBuilder)]
540/// struct SetterStripOptionDefault {
541///     #[builder(default, setter(strip_option))]
542///     value: Option<u32>,
543/// }
544/// ```
545fn _compile_fail_test() {}