derive_builder_core/
builder_field.rs1use std::borrow::Cow;
2
3use proc_macro2::TokenStream;
4use quote::{ToTokens, TokenStreamExt};
5
6#[derive(Debug, Clone)]
32pub struct BuilderField<'a> {
33 pub crate_root: &'a syn::Path,
35 pub field_ident: &'a syn::Ident,
37 pub field_type: BuilderFieldType<'a>,
39 pub field_visibility: Cow<'a, syn::Visibility>,
41 pub attrs: &'a [syn::Attribute],
43}
44
45impl<'a> ToTokens for BuilderField<'a> {
46 fn to_tokens(&self, tokens: &mut TokenStream) {
47 let ident = self.field_ident;
48 let vis = &self.field_visibility;
49 let ty = &self.field_type.with_crate_root(self.crate_root);
50 let attrs = self.attrs;
51 tokens.append_all(quote!(
52 #(#attrs)* #vis #ident: #ty,
53 ));
54 }
55}
56
57impl<'a> BuilderField<'a> {
58 pub fn default_initializer_tokens(&self) -> TokenStream {
60 let ident = self.field_ident;
61 let crate_root = self.crate_root;
62 quote! { #ident : #crate_root::export::core::default::Default::default(), }
63 }
64}
65
66#[derive(Debug, Clone)]
68pub enum BuilderFieldType<'a> {
69 Optional(&'a syn::Type),
71 Precise(&'a syn::Type),
73 Phantom(&'a syn::Type),
83}
84
85impl<'a> BuilderFieldType<'a> {
86 pub fn setter_type_info(&'a self) -> (&'a syn::Type, bool) {
93 match self {
94 BuilderFieldType::Optional(ty) => (ty, true),
95 BuilderFieldType::Precise(ty) => (ty, false),
96 BuilderFieldType::Phantom(_ty) => panic!("phantom fields should never have setters"),
97 }
98 }
99
100 fn with_crate_root(&'a self, crate_root: &'a syn::Path) -> BuilderFieldTypeWithCrateRoot<'a> {
101 BuilderFieldTypeWithCrateRoot {
102 crate_root,
103 field_type: self,
104 }
105 }
106}
107
108struct BuilderFieldTypeWithCrateRoot<'a> {
109 crate_root: &'a syn::Path,
110 field_type: &'a BuilderFieldType<'a>,
111}
112
113impl<'a> ToTokens for BuilderFieldTypeWithCrateRoot<'a> {
114 fn to_tokens(&self, tokens: &mut TokenStream) {
115 let crate_root = self.crate_root;
116 match self.field_type {
117 BuilderFieldType::Optional(ty) => tokens.append_all(quote!(
118 #crate_root::export::core::option::Option<#ty>
119 )),
120 BuilderFieldType::Precise(ty) => ty.to_tokens(tokens),
121 BuilderFieldType::Phantom(ty) => tokens.append_all(quote!(
122 #crate_root::export::core::marker::PhantomData<#ty>
123 )),
124 }
125 }
126}
127
128#[cfg(test)] #[doc(hidden)]
132#[macro_export]
133macro_rules! default_builder_field {
134 () => {{
135 BuilderField {
136 crate_root: &parse_quote!(::db),
139 field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()),
140 field_type: BuilderFieldType::Optional(Box::leak(Box::new(parse_quote!(String)))),
141 field_visibility: ::std::borrow::Cow::Owned(parse_quote!(pub)),
142 attrs: &[parse_quote!(#[some_attr])],
143 }
144 }};
145}
146
147#[cfg(test)]
148mod tests {
149 #[allow(unused_imports)]
150 use super::*;
151
152 #[test]
153 fn setter_enabled() {
154 let field = default_builder_field!();
155
156 assert_eq!(
157 quote!(#field).to_string(),
158 quote!(
159 #[some_attr] pub foo: ::db::export::core::option::Option<String>,
160 )
161 .to_string()
162 );
163 }
164
165 #[test]
166 fn setter_disabled() {
167 let mut field = default_builder_field!();
168 field.field_visibility = Cow::Owned(syn::Visibility::Inherited);
169 field.field_type = match field.field_type {
170 BuilderFieldType::Optional(ty) => BuilderFieldType::Phantom(ty),
171 _ => panic!(),
172 };
173
174 assert_eq!(
175 quote!(#field).to_string(),
176 quote!(
177 #[some_attr]
178 foo: ::db::export::core::marker::PhantomData<String>,
179 )
180 .to_string()
181 );
182 }
183
184 #[test]
185 fn private_field() {
186 let private = Cow::Owned(syn::Visibility::Inherited);
187 let mut field = default_builder_field!();
188 field.field_visibility = private;
189
190 assert_eq!(
191 quote!(#field).to_string(),
192 quote!(
193 #[some_attr]
194 foo: ::db::export::core::option::Option<String>,
195 )
196 .to_string()
197 );
198 }
199}