derivit_core/
setter.rs

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}