struct_builder/lib.rs
1//! Derive builders for your structs.
2//!
3//! Putting `#[builder]` on your struct will derive the builder pattern for it. A new "params" struct will be defined
4//! derived from that follow the builder pattern. The builder can be used to create the struct from only
5//! required fields (those without the [Option] type) and modify the content of the struct.
6//!
7//! A struct builder enforces required fields to be specified and allows optional arguments to be specified post-construction.
8//! This is done by defining a "params" struct that the builder depends on to be initialized. This struct defines all the fields
9//! in the original struct that don't have the "Option" type. Once the builder is initialized with the params, both required and optional fields
10//! can be updated by calling builder methods (using the identifiers `with_<field>`).
11//!
12//! # Examples
13//!
14//! ## Using [macro@builder] to build a request with named fields.
15//! ```
16//! use struct_builder::builder;
17//!
18//! #[builder]
19//! #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
20//! pub struct CreateUserRequest<P> {
21//! pub email: String,
22//! pub first_name: Option<String>,
23//! pub last_name: Option<String>,
24//! pub age: Option<u64>,
25//! pub payload: P
26//! }
27//!
28//! // Inherits attributes and generics from `CreateUserRequest`
29//! let params: CreateUserRequestParams<String> = CreateUserRequestParams {
30//! email: "john.doe@email.com".to_owned(),
31//! payload: "John Doe's User".to_owned()
32//! };
33//!
34//! let request = CreateUserRequest::builder(params)
35//! .with_first_name(Some("John".to_owned()))
36//! .with_age(Some(35))
37//! .build();
38//!
39//! assert_eq!(request.email, "john.doe@email.com".to_owned());
40//! assert_eq!(request.first_name, Some("John".to_owned()));
41//! assert_eq!(request.last_name, None);
42//! assert_eq!(request.age, Some(35));
43//! ```
44//!
45//! ## Using [macro@builder] to build a tuple (unnamed) struct.
46//! ```
47//! use struct_builder::builder;
48//!
49//! /// First, Middle, and Last names.
50//! #[builder]
51//! pub struct FullName(pub String, pub Option<String>, pub String);
52//!
53//! let params = FullNameParams("John".to_owned(), "Doe".to_owned());
54//!
55//! let request = FullName::builder(params)
56//! .with_1(Some("Harold".to_owned()))
57//! .build();
58//!
59//! assert_eq!(request.0, "John".to_owned());
60//! assert_eq!(request.1, Some("Harold".to_owned()));
61//! assert_eq!(request.2, "Doe".to_owned());
62//! ```
63//!
64//! ## Converting a params struct directly with no builder.
65//! ```
66//! use struct_builder::builder;
67//!
68//! #[builder]
69//! pub struct CreateUserRequest {
70//! pub email: String,
71//! pub first_name: Option<String>,
72//! pub last_name: Option<String>,
73//! }
74//!
75//! let request = CreateUserRequest::from(CreateUserRequestParams {
76//! email: "john.doe@email.com".to_owned()
77//! });
78//!
79//! assert_eq!(request.email, "john.doe@email.com".to_owned());
80//! assert_eq!(request.first_name, None);
81//! assert_eq!(request.last_name, None);
82//! ```
83//!
84//! ## Creating a builder directly
85//! ```
86//! use struct_builder::builder;
87//!
88//! #[builder]
89//! pub struct CreateUserRequest {
90//! pub email: String,
91//! pub first_name: Option<String>,
92//! pub last_name: Option<String>,
93//! }
94//!
95//! let request = CreateUserRequest {
96//! email: "john.doe@email.com".to_owned(),
97//! first_name: Some("John".to_owned()),
98//! last_name: None
99//! };
100//!
101//! let rebuilt_request = CreateUserRequestBuilder::from(request)
102//! .with_last_name(Some("Doe".to_owned()))
103//! .build();
104//!
105//! assert_eq!(rebuilt_request.email, "john.doe@email.com".to_owned());
106//! assert_eq!(rebuilt_request.first_name, Some("John".to_owned()));
107//! assert_eq!(rebuilt_request.last_name, Some("Doe".to_owned()));
108//! ```
109
110extern crate proc_macro;
111
112mod components;
113mod struct_builder;
114mod generic_resolution;
115#[cfg(test)]
116mod test_util;
117
118use crate::struct_builder::StructBuilder;
119use quote::quote;
120use syn::{parse_macro_input, ItemStruct};
121
122/// Derive the builder pattern for a struct.
123///
124/// A struct builder enforces required fields to be specified and allows optional arguments to be specified post-construction.
125/// This is done by defining a "params" struct that the builder depends on to be initialized. This struct defines all the fields
126/// in the original struct that don't have the "Option" type. Once the builder is initialized with the params, both required and optional fields
127/// can be updated by calling builder methods (using the identifiers `with_<field>`).
128///
129#[proc_macro_attribute]
130pub fn builder(_attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
131 let original_item = parse_macro_input!(item as ItemStruct);
132 let struct_builder = StructBuilder(original_item.clone());
133
134 proc_macro::TokenStream::from(quote! {
135 #original_item
136 #struct_builder
137 })
138}
139
140
141#[deprecated(
142 since = "0.3.0",
143 note = r#"
144 Please use `#[builder]` macro instead.
145 This macro type does not support inheriting existing attributes, such as other derived traits.
146 "#
147)]
148#[proc_macro_derive(StructBuilder)]
149pub fn derive_builder(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
150 let item = parse_macro_input!(item as ItemStruct);
151 let struct_builder = StructBuilder(item);
152
153 proc_macro::TokenStream::from(quote! { #struct_builder })
154}