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}