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() {}