r_lombok_macros/lib.rs
1//! Macros for [`r-lombok`].
2//!
3//! [`r-lombok-macros`]: https://crates.io/crates/r-lombok-macros
4//! # Example
5//! ```
6//! use std::fmt::Debug;
7//! use r_lombok_macros::{Getter, Setter};
8//! #[derive(Debug, Getter, Setter)]
9//! struct Company {
10//! name: &'static str,
11//! boss: &'static str,
12//! number: u32,
13//! department: Vec<String>,
14//! }
15//!
16//! #[derive(Getter, Setter)]
17//! struct CompanyGen<T> where T: Debug {
18//! name: T,
19//! boss: &'static str,
20//! number: u32,
21//! department: Vec<String>,
22//! }
23//!
24//! #[derive(Getter, Setter)]
25//! struct CompanyWrap {
26//! sub_company: CompanyGen<Company>,
27//! name: &'static str,
28//! }
29//!
30//! // Unit struct
31//! #[derive(Getter, Setter, Debug)]
32//! struct UnitStruct {}
33//!
34//! fn test_getter_setter() {
35//! let mut xp = Company {
36//! name: "xp",
37//! boss: "Big Brother",
38//! number: u32::MAX,
39//! department: vec!["HR".to_owned(), "Finance".to_owned()],
40//! };
41//! println!("xp name = {:?} boss = {:?} number = {:?} department = {:?}", xp.get_name(), xp.get_boss(), xp.get_number(), xp.get_department());
42//! xp.set_name("set_name");
43//! xp.set_boss("set_boss");
44//! xp.set_number(u32::MIN);
45//! xp.set_department(vec!["department".to_owned()]);
46//!
47//!
48//! let xp_t = CompanyGen::<Company> {
49//! name: xp,
50//! boss: "Big Brother",
51//! number: u32::MAX,
52//! department: vec!["HR".to_owned(), "Finance".to_owned()],
53//! };
54//! println!("xp_t name = {:?} boss = {:?} number = {:?} department = {:?}", xp_t.get_name(), xp_t.get_boss(), xp_t.get_number(), xp_t.get_department());
55//!
56//! let xp_wrap = CompanyWrap {
57//! sub_company: xp_t,
58//! name: "xp_wrap",
59//! };
60//! println!("xp_wrap name = {:?} sub_company = {:?}", xp_wrap.get_name(), xp_wrap.get_sub_company().get_name());
61//! }
62//! ```
63
64#![warn(
65clippy::all,
66clippy::dbg_macro,
67clippy::todo,
68clippy::empty_enum,
69clippy::enum_glob_use,
70clippy::mem_forget,
71clippy::unused_self,
72clippy::filter_map_next,
73clippy::needless_continue,
74clippy::needless_borrow,
75clippy::match_wildcard_for_single_variants,
76clippy::if_let_mutex,
77clippy::mismatched_target_os,
78clippy::await_holding_lock,
79clippy::match_on_vec_items,
80clippy::imprecise_flops,
81clippy::suboptimal_flops,
82clippy::lossy_float_literal,
83clippy::rest_pat_in_fully_bound_structs,
84clippy::fn_params_excessive_bools,
85clippy::exit,
86clippy::inefficient_to_string,
87clippy::linkedlist,
88clippy::macro_use_imports,
89clippy::option_option,
90clippy::verbose_file_reads,
91clippy::unnested_or_patterns,
92clippy::str_to_string,
93future_incompatible,
94nonstandard_style,
95missing_debug_implementations,
96missing_docs
97)]
98#![forbid(unsafe_code)]
99
100use proc_macro::TokenStream;
101
102use quote::{quote, ToTokens};
103use syn::parse::Parse;
104
105mod getter;
106mod setter;
107mod data;
108mod accessors;
109mod to_string;
110
111/// field get method prefix
112pub(crate) const METHOD_GET_PREFIX: &str = "get_";
113/// field set method prefix
114pub(crate) const METHOD_SET_PREFIX: &str = "set_";
115
116
117/// like java lombok Getter annotation
118///
119///
120#[proc_macro_derive(Getter)]
121pub fn derive_getter(input: TokenStream) -> TokenStream {
122 expand_with(input, getter::expand)
123}
124
125/// like java lombok Setter annotation
126///
127///
128#[proc_macro_derive(Setter)]
129pub fn derive_setter(input: TokenStream) -> TokenStream {
130 expand_with(input, setter::expand)
131}
132
133/// like java lombok Data annotation, but only contains getter、setter method
134///
135///
136/// ```
137/// use r_lombok_macros::Data;
138/// #[derive(Data)]
139/// struct Company {
140/// name: &'static str,
141/// boss: &'static str,
142/// number: u32,
143/// department: Vec<String>,
144/// }
145///
146/// fn test_data() {
147/// let mut xp = Company {
148/// name: "xp",
149/// boss: "Big Brother",
150/// number: u32::MAX,
151/// department: vec!["HR".to_owned(), "Finance".to_owned()],
152/// };
153/// println!("xp name = {:?} boss = {:?} number = {:?} department = {:?}", xp.get_name(), xp.get_boss(), xp.get_number(), xp.get_department());
154/// xp.set_name("set_name");
155/// xp.set_boss("set_boss");
156/// xp.set_number(u32::MIN);
157/// xp.set_department(vec!["XP-HR".to_owned(), "XP-Finance".to_owned()]);
158/// println!("xp data name = {:?} boss = {:?} number = {:?} department = {:?}", xp.get_name(), xp.get_boss(), xp.get_number(), xp.get_department());
159/// }
160/// ```
161///
162#[proc_macro_derive(Data)]
163pub fn derive_data(input: TokenStream) -> TokenStream {
164 expand_with(input, data::expand)
165}
166
167/// like java lombok ToString annotation
168///
169/// you can use #[derive(Debug)] instead,but ToString contains Debug and impl Display
170/// ```
171/// use r_lombok_macros::ToString;
172/// #[derive(ToString)]
173/// struct Company {
174/// name: &'static str,
175/// boss: &'static str,
176/// number: u32,
177/// department: Vec<String>,
178/// }
179///
180/// fn test_to_string() {
181/// let xp = Company {
182/// name: "xp",
183/// boss: "Big Brother",
184/// number: u32::MAX,
185/// department: vec!["HR".to_owned(), "Finance".to_owned()],
186/// };
187/// println!("xp = {}", xp.to_string());
188/// println!("xp = {:?}", xp.to_string());
189/// }
190/// ```
191///
192#[proc_macro_derive(ToString)]
193pub fn derive_to_string(input: TokenStream) -> TokenStream {
194 expand_with(input, to_string::expand)
195}
196
197/// like java lombok accessors annotation,but contains data and no chain attr
198///
199///```
200/// use r_lombok_macros::Accessors;
201///#[derive(Accessors)]
202/// struct Company {
203/// name: &'static str,
204/// boss: &'static str,
205/// number: u32,
206/// department: Vec<String>,
207/// }
208///
209/// fn test_accessors() {
210/// let mut xp = Company {
211/// name: "xp",
212/// boss: "Big Brother",
213/// number: u32::MAX,
214/// department: vec!["HR".to_owned(), "Finance".to_owned()],
215/// };
216/// println!("xp name = {:?} boss = {:?} number = {:?} department = {:?}", xp.get_name(), xp.get_boss(), xp.get_number(), xp.get_department());
217/// xp.set_name("set_name").set_boss("set_boss").set_number(u32::MIN).set_department(vec!["XP-HR".to_owned(), "XP-Finance".to_owned()]);
218/// println!("xp accessors name = {:?} boss = {:?} number = {:?} department = {:?}", xp.get_name(), xp.get_boss(), xp.get_number(), xp.get_department());
219/// }
220/// ```
221///
222#[proc_macro_derive(Accessors)]
223pub fn derive_accessors(input: TokenStream) -> TokenStream {
224 expand_with(input, accessors::expand)
225}
226
227fn expand_with<F, I, K>(input: TokenStream, f: F) -> TokenStream
228 where
229 F: FnOnce(I) -> syn::Result<K>,
230 I: Parse,
231 K: ToTokens,
232{
233 let r = syn::parse(input);
234 expand(r.and_then(f))
235}
236
237fn expand<T>(result: syn::Result<T>) -> TokenStream
238 where
239 T: ToTokens,
240{
241 match result {
242 Ok(tokens) => {
243 let tokens = (quote! { #tokens }).into();
244 if std::env::var_os("R_LOMBOK_MACROS_DEBUG").is_some() {
245 eprintln!("{}", tokens);
246 }
247 tokens
248 }
249 Err(err) => err.into_compile_error().into(),
250 }
251}