1use super::FnGenerics;
2use darling::FromMeta;
3use quote::{format_ident, quote, ToTokens};
4
5#[derive(Default, FromMeta)]
6pub struct FieldSetterOptions {
7 pub rename: Option<syn::Ident>,
8 pub style: Option<SetterStyle>,
9 pub attrs: Option<super::Attributes>,
10 #[darling(default, rename = "skip")]
11 pub ignore: bool,
12 #[darling(default, rename = "const")]
13 pub compile_time: bool,
14 pub vis: Option<syn::Visibility>,
15 #[darling(default)]
16 pub bound: FnGenerics,
17}
18
19#[derive(FromMeta)]
20pub struct StructSetterOptions {
21 pub prefix: Option<syn::Ident>,
22 #[darling(default)]
23 pub style: SetterStyle,
24 #[darling(default, rename = "skip")]
25 pub ignore: bool,
26 pub vis_all: Option<syn::Visibility>,
27}
28
29impl Default for StructSetterOptions {
30 fn default() -> Self {
31 Self {
32 prefix: Some(format_ident!("set")),
33 style: SetterStyle::Move,
34 ignore: false,
35 vis_all: None,
36 }
37 }
38}
39
40#[derive(Default, FromMeta, Clone, Copy)]
41pub enum SetterStyle {
42 #[darling(rename = "ref")]
43 Ref,
44 #[darling(rename = "move")]
45 #[default]
46 Move,
47 #[darling(rename = "into")]
48 Into,
49 #[darling(rename = "try_into")]
50 TryInto,
51}
52
53impl SetterStyle {
54 #[allow(clippy::too_many_arguments)]
55 fn to_setter(
56 &self,
57 fn_vis: &syn::Visibility,
58 bound: Option<&syn::Generics>,
59 field_name: &syn::Ident,
60 field_ty: &syn::Type,
61 fn_name: &syn::Ident,
62 compile_time: bool,
63 attrs: Option<super::Attributes>,
64 ) -> proc_macro2::TokenStream {
65 let compile_time = if compile_time {
66 quote! { const }
67 } else {
68 quote! {}
69 };
70 match self {
71 Self::Ref => quote! {
72 #attrs
73 #[inline]
74 #fn_vis #compile_time fn #fn_name #bound (&mut self, val: #field_ty) {
75 self.#field_name = val;
76 }
77
78 },
79 Self::Move => quote! {
80 #attrs
81 #[inline]
82 #fn_vis #compile_time fn #fn_name #bound (mut self, val: #field_ty) -> Self {
83 self.#field_name = val;
84 self
85 }
86
87 },
88 Self::Into => quote! {
89 #attrs
90 #[inline]
91 #fn_vis #compile_time fn #fn_name #bound (mut self, val: impl core::convert::Into<#field_ty>) -> Self {
92 self.#field_name = ::core::convert::Into::into(val);
93 self
94 }
95
96 },
97 Self::TryInto => {
98 let bound = bound.map(|tt| {
99 let bound = format!(
100 "{}, Error>",
101 tt.to_token_stream().to_string().trim_end_matches('>')
102 );
103 syn::parse_str::<syn::Generics>(&bound).unwrap()
104 });
105 quote! {
106 #attrs
107 #[inline]
108 #fn_vis #compile_time fn #fn_name #bound (mut self, val: impl ::core::convert::TryInto<#field_ty, Error = Error>) -> ::core::result::Result<Self, Error> {
109 self.#field_name = ::core::convert::TryInto::try_into(val)?;
110 ::core::result::Result::Ok(self)
111 }
112 }
113 }
114 }
115 }
116}
117
118pub struct FieldSetter {
119 pub vis: syn::Visibility,
120 pub bound: Option<syn::Generics>,
121 pub field_name: syn::Ident,
122 pub field_ty: syn::Type,
123 pub fn_name: syn::Ident,
124 pub style: SetterStyle,
125 pub attrs: Option<super::Attributes>,
126 pub compile_time: bool,
127}
128
129impl ToTokens for FieldSetter {
130 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
131 let fn_vis = &self.vis;
132 let bound = self.bound.as_ref();
133 let field_name = &self.field_name;
134 let field_ty = &self.field_ty;
135 let fn_name = &self.fn_name;
136 let style = &self.style;
137 tokens.extend(style.to_setter(
138 fn_vis,
139 bound,
140 field_name,
141 field_ty,
142 fn_name,
143 self.compile_time,
144 self.attrs.clone(),
145 ));
146 }
147}