lombok_macros/lib.rs
1//! lombok-macros
2//!
3//! A Rust procedural macro collection providing Lombok-like functionality.
4//! Automatically generates getters/setters with field-level visibility control,
5//! custom Debug implementations with field skipping, and Display trait implementations.
6//! Supports structs, enums, generics and lifetimes.
7
8pub(crate) mod config;
9pub(crate) mod func;
10pub(crate) mod generate;
11pub(crate) mod parse;
12pub(crate) mod visibility;
13
14pub(crate) use config::*;
15pub(crate) use func::*;
16pub(crate) use generate::*;
17pub(crate) use parse::*;
18pub(crate) use visibility::*;
19
20pub(crate) use proc_macro::TokenStream;
21pub(crate) use proc_macro2::{
22 TokenStream as TokenStream2, TokenTree as TokenTree2, token_stream::IntoIter,
23};
24pub(crate) use quote::{ToTokens, format_ident, quote};
25pub(crate) use std::{collections::HashMap, str::FromStr};
26pub(crate) use syn::{
27 Data, DeriveInput, Field,
28 GenericParam::{self},
29 Ident, Lifetime,
30 Type::{self},
31 TypeParam, WhereClause, parse_macro_input,
32};
33
34/// This is an example of how to use the `Lombok` procedural macro with `get` attributes.
35///
36/// The `Lombok` procedural macro is used to automatically generate getter methods for struct fields.
37/// The `get` attribute controls the visibility of the generated getter method.
38///
39/// Example:
40///
41/// ```rust
42/// use lombok_macros::*;
43///
44/// #[derive(Getter, Clone)]
45/// struct LombokTest2<'a, 'b, T: Clone> {
46/// #[get(pub(crate))]
47/// list: Vec<String>,
48/// #[get(pub(crate))]
49/// opt_str_lifetime_a: Option<&'a T>,
50/// opt_str_lifetime_b: Option<&'b str>,
51/// }
52/// let list: Vec<String> = vec!["hello".to_string(), "world".to_string()];
53/// let data2: LombokTest2<usize> = LombokTest2 {
54/// list: list.clone(),
55/// opt_str_lifetime_a: None,
56/// opt_str_lifetime_b: None,
57/// };
58/// let get_list: Vec<String> = data2.get_list().clone();
59/// assert_eq!(get_list, list);
60/// ```
61#[proc_macro_derive(Getter, attributes(get))]
62pub fn getter(input: TokenStream) -> TokenStream {
63 inner_lombok_data(input, true, false, false)
64}
65
66/// This is an example of how to use the `Lombok` procedural macro with `get_mut` attributes.
67///
68/// The `Lombok` procedural macro is used to automatically generate mutable getters for struct fields.
69/// The `get_mut` attribute controls the visibility of the mutable getter function.
70///
71/// Example:
72///
73/// ```rust
74/// use lombok_macros::*;
75///
76/// #[derive(GetterMut, Clone)]
77/// struct LombokTest2<'a, 'b, T: Clone> {
78/// #[get_mut(pub(crate))]
79/// list: Vec<String>,
80/// #[get_mut(pub(crate))]
81/// opt_str_lifetime_a: Option<&'a T>,
82/// opt_str_lifetime_b: Option<&'b str>,
83/// }
84/// let list: Vec<String> = vec!["hello".to_string(), "world".to_string()];
85/// let mut data2: LombokTest2<usize> = LombokTest2 {
86/// list: list.clone(),
87/// opt_str_lifetime_a: None,
88/// opt_str_lifetime_b: None,
89/// };
90/// let get_list: Vec<String> = data2.get_mut_list().clone();
91/// assert_eq!(get_list, list);
92/// ```
93#[proc_macro_derive(GetterMut, attributes(get_mut))]
94pub fn getter_mut(input: TokenStream) -> TokenStream {
95 inner_lombok_data(input, false, true, false)
96}
97
98/// This is an example of how to use the `Lombok` procedural macro with `set` attributes.
99///
100/// The `Lombok` procedural macro is used to automatically generate setters for struct fields.
101/// The `set` attribute controls the visibility of the setter function.
102///
103/// Example:
104///
105/// ```rust
106/// use lombok_macros::*;
107///
108/// #[derive(Setter, Debug, Clone)]
109/// struct LombokTest<'a, 'b, T: Clone> {
110/// #[set(pub(crate))]
111/// list: Vec<String>,
112/// opt_str_lifetime_a: Option<&'a T>,
113/// #[set(private)]
114/// opt_str_lifetime_b: Option<&'b str>,
115/// }
116/// let mut data: LombokTest<usize> = LombokTest {
117/// list: Vec::new(),
118/// opt_str_lifetime_a: None,
119/// opt_str_lifetime_b: None,
120/// };
121/// let list: Vec<String> = vec!["hello".to_string(), "world".to_string()];
122/// data.set_list(list.clone());
123/// match data.list {
124/// left_val => {
125/// assert_eq!(*left_val, list);
126/// }
127/// }
128/// ```
129#[proc_macro_derive(Setter, attributes(set))]
130pub fn setter(input: TokenStream) -> TokenStream {
131 inner_lombok_data(input, false, false, true)
132}
133
134/// This is an example of how to use the `Lombok` procedural macro with `get`, `get_mut`, and `set` attributes.
135///
136/// The `Lombok` procedural macro is used to automatically generate getters, mutable getters, and setters for struct fields.
137/// The `get` and `get_mut` attributes control the visibility of the getter functions, while the `set` attribute controls
138/// the visibility of the setter function.
139///
140/// Example:
141///
142/// ```rust
143/// use lombok_macros::*;
144///
145/// #[derive(Data, Debug, Clone)]
146/// struct LombokTest<'a, 'b, T: Clone> {
147/// #[get(pub(crate))]
148/// #[set(pub(crate))]
149/// list: Vec<String>,
150/// #[get(pub(crate))]
151/// opt_str_lifetime_a: Option<&'a T>,
152/// #[set(private)]
153/// opt_str_lifetime_b: Option<&'b str>,
154/// }
155/// let mut data: LombokTest<usize> = LombokTest {
156/// list: Vec::new(),
157/// opt_str_lifetime_a: None,
158/// opt_str_lifetime_b: None,
159/// };
160/// let list: Vec<String> = vec!["hello".to_string(), "world".to_string()];
161/// data.set_list(list.clone());
162/// match data.get_list() {
163/// left_val => {
164/// assert_eq!(*left_val, list);
165/// }
166/// }
167/// ```
168#[proc_macro_derive(Data, attributes(get, get_mut, set))]
169pub fn data(input: TokenStream) -> TokenStream {
170 let mut result: TokenStream2 = TokenStream2::new();
171 let lombok_data: TokenStream = inner_lombok_data(input.clone(), true, true, true);
172 result.extend(
173 lombok_data
174 .to_string()
175 .parse::<TokenStream2>()
176 .unwrap_or_default(),
177 );
178 result.into()
179}
180
181/// A procedural macro that implements the `std::fmt::Display` trait for a type,
182/// using the standard debug format (`{:?}`) for formatting.
183///
184/// This macro derives the `Display` implementation for a type, allowing it to be formatted
185/// using `{:?}` in formatting macros. It uses the `inner_display_debug` function to generate
186/// the implementation with the standard debug format.
187///
188/// # Parameters
189/// - `input`: The input token stream representing the Rust item (struct, enum, etc.)
190/// for which the `Display` implementation will be generated.
191///
192/// # Returns
193/// - `TokenStream`: The generated `std::fmt::Display` implementation for the type
194/// using the standard debug format.
195#[proc_macro_derive(DisplayDebug)]
196pub fn display_debug(input: TokenStream) -> TokenStream {
197 inner_display_debug(input)
198}
199
200/// A procedural macro that implements the `std::fmt::Display` trait for a type,
201/// using the detailed debug format (`{:#?}`) for formatting.
202///
203/// This macro derives the `Display` implementation for a type, allowing it to be formatted
204/// using `{:#?}` in formatting macros. It uses the `inner_display_debug_format` function
205/// to generate the implementation with the detailed debug format.
206///
207/// # Parameters
208/// - `input`: The input token stream representing the Rust item (struct, enum, etc.)
209/// for which the `Display` implementation will be generated.
210///
211/// # Returns
212/// - `TokenStream`: The generated `std::fmt::Display` implementation for the type
213/// using the detailed debug format.
214#[proc_macro_derive(DisplayDebugFormat)]
215pub fn display_debug_format(input: TokenStream) -> TokenStream {
216 inner_display_debug_format(input)
217}
218
219/// A procedural macro that implements the `std::fmt::Debug` trait for a type,
220/// with support for the `#[debug(skip)]` attribute to skip specific fields.
221///
222/// This macro derives a custom Debug implementation that behaves like the standard
223/// library's Debug derive, but allows individual fields to be excluded from the
224/// debug output by annotating them with `#[debug(skip)]`.
225///
226/// # Supported Attributes
227/// - `#[debug(skip)]`: Excludes the field from the debug output
228///
229/// # Examples
230///
231/// ## Struct Example
232/// ```rust
233/// use lombok_macros::*;
234///
235/// #[derive(CustomDebug)]
236/// struct User {
237/// name: String,
238/// #[debug(skip)]
239/// password: String,
240/// email: String,
241/// }
242///
243/// let user = User {
244/// name: "Alice".to_string(),
245/// password: "secret123".to_string(),
246/// email: "alice@example.com".to_string(),
247/// };
248/// let expected_debug = "User { name: \"Alice\", email: \"alice@example.com\" }";
249/// assert_eq!(format!("{:?}", user), expected_debug);
250/// ```
251///
252/// ## Enum Example
253/// ```rust
254/// use lombok_macros::*;
255///
256/// #[derive(CustomDebug)]
257/// enum Response {
258/// Success { data: String },
259/// Error {
260/// message: String,
261/// #[debug(skip)]
262/// internal_code: u32,
263/// },
264/// }
265///
266/// let success = Response::Success { data: "Hello".to_string() };
267/// let error = Response::Error { message: "Failed".to_string(), internal_code: 500 };
268/// let expected_success = "Success { data: \"Hello\" }";
269/// let expected_error = "Error { message: \"Failed\" }";
270/// assert_eq!(format!("{:?}", success), expected_success);
271/// assert_eq!(format!("{:?}", error), expected_error);
272/// ```
273///
274/// # Parameters
275/// - `input`: The input token stream representing the Rust item (struct, enum, etc.)
276/// for which the Debug implementation will be generated.
277///
278/// # Returns
279/// - `TokenStream`: The generated `std::fmt::Debug` implementation for the type
280/// that respects the `#[debug(skip)]` attribute.
281#[proc_macro_derive(CustomDebug, attributes(debug))]
282pub fn custom_debug(input: TokenStream) -> TokenStream {
283 inner_custom_debug(input)
284}
285
286/// A procedural macro that generates a constructor function for structs.
287///
288/// This macro automatically generates a `new` function that takes all non-skipped fields
289/// as parameters and returns a new instance of the struct. Fields marked with `#[new(skip)]`
290/// will be initialized with their default values.
291///
292/// # Supported Attributes
293/// - `#[new(skip)]`: Excludes the field from constructor parameters and uses default initialization
294/// - `#[new(pub)]`: Generates a public constructor
295/// - `#[new(pub(crate))]`: Generates a crate-visible constructor
296/// - `#[new(pub(super))]`: Generates a constructor visible to parent module
297/// - `#[new(private)]`: Generates a private constructor
298///
299/// # Default Behavior
300/// - The generated constructor is `pub` by default
301/// - All fields are included in the constructor unless marked with `#[new(skip)]`
302/// - Skipped fields are initialized using `Default::default()`
303///
304/// # Examples
305///
306/// ## Basic Usage
307/// ```rust
308/// use lombok_macros::*;
309///
310/// #[derive(New)]
311/// struct Person {
312/// name: String,
313/// age: u32,
314/// }
315///
316/// let person = Person::new("Alice".to_string(), 30);
317/// assert_eq!(person.name, "Alice");
318/// assert_eq!(person.age, 30);
319/// ```
320///
321/// ## With Skip Attribute
322/// ```rust
323/// use lombok_macros::*;
324///
325/// #[derive(New)]
326/// struct User {
327/// username: String,
328/// email: String,
329/// #[new(skip)]
330/// created_at: String,
331/// }
332///
333/// let user = User::new("alice".to_string(), "alice@example.com".to_string());
334/// assert_eq!(user.username, "alice");
335/// assert_eq!(user.email, "alice@example.com");
336/// assert_eq!(user.created_at, ""); // skipped field defaults to empty string
337/// ```
338///
339/// ## With Visibility Control
340/// ```rust
341/// use lombok_macros::*;
342///
343/// #[derive(New)]
344/// #[new(pub(crate))]
345/// struct InternalStruct {
346/// value: i32,
347/// }
348/// ```
349///
350/// # Parameters
351/// - `input`: The input token stream representing the struct for which to generate the constructor.
352///
353/// # Returns
354/// - `TokenStream`: The generated constructor implementation.
355#[proc_macro_derive(New, attributes(new))]
356pub fn new(input: TokenStream) -> TokenStream {
357 let derive_input: DeriveInput = parse_macro_input!(input as DeriveInput);
358 let visibility: Visibility = parse_new_visibility(&derive_input);
359 inner_new_constructor(&derive_input, visibility)
360}