1use crate::FieldHandling::{IsOption, Other, Required};
13use darling::util::PathList;
14use darling::{FromAttributes, FromDeriveInput};
15use itertools::MultiUnzip;
16use proc_macro2::{Ident, Literal, Span, TokenStream};
17use quote::{format_ident, quote, ToTokens};
18use std::cmp::PartialEq;
19use std::default::Default;
20use std::{fmt, iter};
21use syn::punctuated::Punctuated;
22use syn::spanned::Spanned;
23use syn::token::Where;
24use syn::{
25 parse_quote, Attribute, Data, DeriveInput, Error, Field, Fields, GenericParam, LitStr, Meta, Path,
26 Token, Type, TypePath, WhereClause, WherePredicate,
27};
28
29const HELPER_IDENT: &str = "optionable";
30const HELPER_ATTR_IDENT: &str = "optionable_attr";
31const ERR_MSG_HELPER_ATTR_ENUM_VARIANTS: &str =
32 "#[optionable] helper attributes not supported on enum variant level.";
33
34#[derive(FromDeriveInput)]
35#[darling(attributes(optionable))]
36struct TypeHelperAttributes {
38 derive: Option<PathList>,
40 #[darling(default=default_suffix)]
41 suffix: LitStr,
43 no_convert: Option<()>,
45}
46
47#[derive(FromAttributes)]
48#[darling(attributes(optionable))]
49struct FieldHelperAttributes {
51 required: Option<()>,
53}
54
55fn default_suffix() -> LitStr {
56 LitStr::new("Opt", Span::call_site())
57}
58
59#[must_use]
61pub fn attribute_no_convert() -> Attribute {
62 parse_quote!(#[optionable(no_convert)])
63}
64
65#[must_use]
67pub fn attribute_suffix(suffix: &str) -> Attribute {
68 parse_quote!(#[optionable(suffix=#suffix)])
69}
70
71#[must_use]
74pub fn attribute_derives(derives: &PathList) -> Attribute {
75 parse_quote!(#[optionable(derive(#(#derives),*))])
76}
77
78#[allow(clippy::too_many_lines)]
84pub fn derive_optionable(input: DeriveInput) -> syn::Result<TokenStream> {
85 let attrs = TypeHelperAttributes::from_derive_input(&input)?;
86 let forward_attrs = forwarded_attributes(&input.attrs);
87 let vis = input.vis;
88 let type_ident_opt = Ident::new(
89 &(input.ident.to_string() + &attrs.suffix.value()),
90 input.ident.span(),
91 );
92 let type_ident = &input.ident;
93
94 let generics_colon = (!input.generics.params.is_empty()).then(|| quote! {::});
95 let (impl_generics, ty_generics, _) = input.generics.split_for_impl();
96 let mut where_clause = input
97 .generics
98 .where_clause
99 .clone()
100 .unwrap_or_else(|| WhereClause {
101 where_token: Where::default(),
102 predicates: Punctuated::default(),
103 });
104 let where_clause_convert = attrs.no_convert.is_none().then(|| {
105 let mut where_clause = where_clause.clone();
106
107 patch_where_clause_bounds(&mut where_clause, &input.generics.params, |_| {
108 quote!(::optionable::OptionableConvert)
109 });
110 where_clause
111 });
112 patch_where_clause_bounds(&mut where_clause, &input.generics.params, |_| {
113 quote!(::optionable::Optionable)
114 });
115
116 let impls_optionable = quote! {
119 #[automatically_derived]
120 impl #impl_generics ::optionable::Optionable for #type_ident #ty_generics #where_clause {
121 type Optioned = #type_ident_opt #ty_generics;
122 }
123
124 #[automatically_derived]
125 impl #impl_generics ::optionable::Optionable for #type_ident_opt #ty_generics #where_clause {
126 type Optioned = #type_ident_opt #ty_generics;
127 }
128 };
129
130 let derives = attrs.derive.unwrap_or_default();
133 let skip_optionable_if_serde_serialize = derives
134 .iter()
135 .any(is_serialize)
136 .then(|| quote!(#[serde(skip_serializing_if = "Option::is_none")]));
137 let derives = (!derives
138 .iter()
139 .map(ToTokens::to_token_stream)
140 .collect::<Vec<_>>()
141 .is_empty())
142 .then(|| quote! {#[derive(#(#derives),*)]});
143
144 match input.data {
145 Data::Struct(s) => {
146 let fields = into_field_handling(s.fields)?;
147 let unnamed_struct_semicolon =
148 (fields.struct_type == StructType::Unnamed).then(|| quote!(;));
149 let optioned_fields =
150 optioned_fields(&fields, skip_optionable_if_serde_serialize.as_ref());
151
152 let impl_optionable_convert = attrs.no_convert.is_none().then(|| {
153 let into_optioned_fields = into_optioned(&fields, |selector| quote! { self.#selector });
154 let try_from_optioned_fields =
155 try_from_optioned(&fields, |selector| quote! { value.#selector });
156 let merge_fields = merge_fields(
157 &fields,
158 |selector| quote! { self.#selector },
159 |selector| quote! { other.#selector },
160 true);
161 quote! {
162 #[automatically_derived]
163 impl #impl_generics ::optionable::OptionableConvert for #type_ident #ty_generics #where_clause_convert {
164 fn into_optioned(self) -> #type_ident_opt #ty_generics {
165 #type_ident_opt #generics_colon #ty_generics #into_optioned_fields
166 }
167
168 fn try_from_optioned(value: #type_ident_opt #ty_generics) -> Result<Self,::optionable::optionable::Error>{
169 Ok(Self #try_from_optioned_fields)
170 }
171
172 fn merge(&mut self, other: #type_ident_opt #ty_generics) -> Result<(), ::optionable::optionable::Error>{
173 #merge_fields
174 Ok(())
175 }
176 }
177 }
178 });
179
180 Ok(quote! {
181 #[automatically_derived]
182 #derives
183 #forward_attrs
184 #vis struct #type_ident_opt #impl_generics #where_clause #optioned_fields #unnamed_struct_semicolon
185
186 #impls_optionable
187
188 #impl_optionable_convert
189 })
190 }
191 Data::Enum(e) => {
192 let self_prefix = quote! {self_};
193 let other_prefix = quote! {other_};
194
195 let variants = e
196 .variants
197 .into_iter()
198 .map(|v| {
199 error_on_helper_attributes(&v.attrs, ERR_MSG_HELPER_ATTR_ENUM_VARIANTS)?;
200 Ok::<_, Error>((v.ident, into_field_handling(v.fields)?))
201 })
202 .collect::<Result<Vec<_>, _>>()?;
203
204 let optioned_variants = variants.iter().map(|(variant, f)| {
205 let fields = optioned_fields(f, skip_optionable_if_serde_serialize.as_ref());
206 quote!( #variant #fields )
207 });
208
209 let impl_optionable_convert = attrs.no_convert.is_none().then(|| {
210 let (into_variants, try_from_variants, merge_variants): (Vec<_>, Vec<_>, Vec<_>) = variants
211 .iter()
212 .map(|(variant, f)| {
213 let fields_into = into_optioned(f, |selector| {
214 format_ident!("{self_prefix}{selector}").to_token_stream()
215 });
216 let fields_try_from = try_from_optioned(f, |selector| {
217 format_ident!("{other_prefix}{selector}").to_token_stream()
218 });
219 let fields_merge = merge_fields(f,
220 |selector| format_ident!("{self_prefix}{selector}").to_token_stream(),
221 |selector| format_ident!("{other_prefix}{selector}").to_token_stream(),
222 false);
223 let self_destructure = destructure(f, &self_prefix)?;
224 let other_destructure = destructure(f, &other_prefix)?;
225 Ok::<_, Error>((
226 quote!( Self::#variant #self_destructure => #type_ident_opt::#variant #fields_into ),
227 quote!( #type_ident_opt::#variant #other_destructure => Self::#variant #fields_try_from ),
228 quote!( #type_ident_opt::#variant #other_destructure => {
229 if let Self::#variant #self_destructure = self {
230 #fields_merge
231 } else {
232 *self = Self::try_from_optioned(#type_ident_opt::#variant #other_destructure)?;
233 }
234 })
235 ))
236 })
237 .collect::<Result<Vec<_>, _>>()?
238 .into_iter().multiunzip();
239 Ok::<_, Error>(quote! {
240 #[automatically_derived]
241 impl #impl_generics ::optionable::OptionableConvert for #type_ident #ty_generics #where_clause_convert {
242 fn into_optioned(self) -> #type_ident_opt #ty_generics {
243 match self {
244 #(#into_variants),*
245 }
246 }
247
248 fn try_from_optioned(other: #type_ident_opt #ty_generics)->Result<Self,::optionable::optionable::Error>{
249 Ok(match other{
250 #(#try_from_variants),*
251 })
252 }
253
254 fn merge(&mut self, other: #type_ident_opt #ty_generics) -> Result<(), ::optionable::optionable::Error>{
255 match other{
256 #(#merge_variants),*
257 }
258 Ok(())
259 }
260 }
261 })
262 }).transpose()?;
263
264 Ok(quote!(
265 #[automatically_derived]
266 #derives
267 #forward_attrs
268 #vis enum #type_ident_opt #impl_generics #where_clause {
269 #(#optioned_variants),*
270 }
271
272 #impls_optionable
273
274 #impl_optionable_convert
275 ))
276 }
277 Data::Union(_) => error("#[derive(Optionable)] not supported for unit structs"),
278 }
279}
280
281fn destructure(fields: &FieldsParsed, prefix: &TokenStream) -> Result<TokenStream, Error> {
284 Ok(match fields.struct_type {
285 StructType::Named => {
286 let fields = fields
287 .fields
288 .iter()
289 .map(|f| {
290 let ident = f.field.ident.as_ref().ok_or::<Error>(
291 error::<_, Error>(format!(
292 "expected field name but none present for {f:?}"
293 ))
294 .unwrap_err(),
295 )?;
296 let prefixed_ident = format_ident!("{1}{0}", ident.clone(), prefix.to_string());
297 Ok::<_, Error>(quote! {#ident: #prefixed_ident})
298 })
299 .collect::<Result<Vec<_>, _>>()?;
300 quote! {{#(#fields),*}}
301 }
302 StructType::Unnamed => {
303 let indices: Vec<_> = (0..fields.fields.len())
304 .map(|i| {
305 let prefixed = format_ident!("{1}{0}", i, prefix.to_string());
306 quote! {#prefixed}
307 })
308 .collect();
309 quote! {(#(#indices),*)}
310 }
311 StructType::Unit => quote! {},
312 })
313}
314
315fn optioned_fields(fields: &FieldsParsed, serde_attributes: Option<&TokenStream>) -> TokenStream {
319 let fields_token = fields.fields.iter().map(
320 |FieldParsed {
321 field: Field { attrs,vis, ident, ty, .. },
322 handling,
323 }| {
324 let forward_attrs = forwarded_attributes(attrs);
325 let optioned_ty = optioned_ty(ty);
326 let colon = ident.as_ref().map(|_| quote! {:});
327 match handling {
328 Required => quote! {#forward_attrs #vis #ident #colon #ty},
329 IsOption => quote! {#forward_attrs #serde_attributes #vis #ident #colon #optioned_ty},
330 Other => quote! {#forward_attrs #serde_attributes #vis #ident #colon Option<#optioned_ty>},
331 }
332 },
333 );
334 struct_wrapper(fields_token, &fields.struct_type)
335}
336
337fn into_optioned(
341 fields: &FieldsParsed,
342 self_selector_fn: impl Fn(&TokenStream) -> TokenStream,
343) -> TokenStream {
344 let fields_token = fields.fields.iter().enumerate().map(|(i, FieldParsed { field: Field { ident, ty, .. }, handling })| {
345 let colon = ident.as_ref().map(|_| quote! {:});
346 let selector = ident.as_ref().map_or_else(|| {
347 let i = Literal::usize_unsuffixed(i);
348 quote! {#i}
349 }, ToTokens::to_token_stream);
350 let self_selector = self_selector_fn(&selector);
351 match (handling, is_self_resolving_optioned(ty)) {
352 (Required, _) | (IsOption, true) => quote! {#ident #colon #self_selector},
353 (IsOption, false) => quote! {#ident #colon <#ty as ::optionable::OptionableConvert>::into_optioned(#self_selector)},
354 (Other, true) => quote! {#ident #colon Some(#self_selector)},
355 (Other, false) => quote! {#ident #colon Some(<#ty as ::optionable::OptionableConvert>::into_optioned(#self_selector))}
356 }
357 });
358 struct_wrapper(fields_token, &fields.struct_type)
359}
360
361fn try_from_optioned(
365 fields: &FieldsParsed,
366 value_selector_fn: impl Fn(&TokenStream) -> TokenStream,
367) -> TokenStream {
368 let fields_token = fields.fields.iter().enumerate().map(|(i, FieldParsed { field: Field { ident, ty, .. }, handling })| {
369 let colon = ident.as_ref().map(|_| quote! {:});
370 let selector = ident.as_ref().map_or_else(|| {
371 let i = Literal::usize_unsuffixed(i);
372 quote! {#i}
373 }, ToTokens::to_token_stream);
374 let value_selector = value_selector_fn(&selector);
375 match (handling, is_self_resolving_optioned(ty)) {
376 (Required, _) | (IsOption, true) => quote! {#ident #colon value.#selector},
377 (IsOption, false) => quote! {
378 #ident #colon <#ty as ::optionable::OptionableConvert>::try_from_optioned(
379 #value_selector
380 )?
381 },
382 (Other, true) => {
383 let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
384 quote! {
385 #ident #colon #value_selector.ok_or(optionable::optionable::Error{ missing_fields: std::vec![#selector_quoted] })?
386 }
387 }
388 (Other, false) => {
389 let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
390 quote! {
391 #ident #colon <#ty as ::optionable::OptionableConvert>::try_from_optioned(
392 #value_selector.ok_or(optionable::optionable::Error{ missing_fields: std::vec![#selector_quoted] })?
393 )?
394 }
395 }
396 }
397 });
398
399 struct_wrapper(fields_token, &fields.struct_type)
400}
401
402fn merge_fields(
408 fields: &FieldsParsed,
409 self_selector_fn: impl Fn(&TokenStream) -> TokenStream,
410 other_selector_fn: impl Fn(&TokenStream) -> TokenStream,
411 merge_self_mut: bool,
412) -> TokenStream {
413 let fields_token = fields.fields.iter().enumerate().map(
414 |(
415 i,
416 FieldParsed {
417 field: Field { ident, ty, .. },
418 handling,
419 },
420 )| {
421 let selector = ident.as_ref().map_or_else(
422 || {
423 let i = Literal::usize_unsuffixed(i);
424 quote! {#i}
425 },
426 ToTokens::to_token_stream,
427 );
428 let self_merge_mut_modifier = merge_self_mut.then(|| quote! {&mut});
429 let deref_modifier = (!merge_self_mut).then(|| quote! {*});
430 let self_selector = self_selector_fn(&selector);
431 let other_selector = other_selector_fn(&selector);
432 match (handling, is_self_resolving_optioned(ty)) {
433 (Required, _) | (IsOption, true) => quote! {#deref_modifier #self_selector = #other_selector;},
434 (IsOption, false) => quote! {
435 <#ty as ::optionable::OptionableConvert>::merge(#self_merge_mut_modifier #self_selector, #other_selector)?;
436 },
437 (Other, true) => quote! {
438 if let Some(other_value)=#other_selector{
439 #deref_modifier #self_selector = other_value;
440 }
441 },
442 (Other, false) => quote! {
443 if let Some(other_value)=#other_selector{
444 <#ty as ::optionable::OptionableConvert>::merge(#self_merge_mut_modifier #self_selector, other_value)?;
445 }
446 }
447 }
448 },
449 );
450
451 quote! {
452 #(#fields_token)*
453 }
454}
455
456fn struct_wrapper(
459 tokens: impl Iterator<Item = TokenStream>,
460 struct_name_type: &StructType,
461) -> TokenStream {
462 match struct_name_type {
463 StructType::Named => quote!({#(#tokens),*}),
464 StructType::Unnamed => quote!((#(#tokens),*)),
465 StructType::Unit => quote!(),
466 }
467}
468
469fn patch_where_clause_bounds(
473 where_clause: &mut WhereClause,
474 params: &Punctuated<GenericParam, Token![,]>,
475 predicate: impl Fn(&Type) -> TokenStream,
476) {
477 params.iter().for_each(|param| {
478 if let GenericParam::Type(type_param) = param {
479 let path = &Type::Path(TypePath {
480 qself: None,
481 path: type_param.ident.clone().into(),
482 });
483 add_where_clause_predicate(where_clause, path, &predicate);
484 }
485 });
486}
487
488fn add_where_clause_predicate(
491 where_clause: &mut WhereClause,
492 ty: &Type,
493 entry: impl Fn(&Type) -> TokenStream,
494) {
495 let bounds = where_clause.predicates.iter_mut().find_map(|pred| {
496 if let WherePredicate::Type(pred_ty) = pred
497 && *ty == pred_ty.bounded_ty
498 {
499 Some(&mut pred_ty.bounds)
500 } else {
501 None
502 }
503 });
504 let entry = entry(ty);
505 if let Some(bounds) = bounds {
506 bounds.push(parse_quote!(#entry));
507 } else {
508 where_clause.predicates.push(parse_quote!(#ty: #entry));
509 }
510}
511
512fn error_on_helper_attributes(attrs: &[Attribute], err_msg: &'static str) -> syn::Result<()> {
515 if attrs
516 .iter()
517 .filter(|attr| {
518 println!("{}", attr.path().to_token_stream());
519 attr.path().is_ident(HELPER_IDENT)
520 })
521 .collect::<Vec<_>>()
522 .is_empty()
523 {
524 Ok(())
525 } else {
526 error(err_msg)
527 }
528}
529
530fn into_field_handling(fields: Fields) -> Result<FieldsParsed, Error> {
533 let struct_named = match &fields {
534 Fields::Named(_) => StructType::Named,
535 Fields::Unnamed(_) => StructType::Unnamed,
536 Fields::Unit => StructType::Unit,
537 };
538
539 let fields_iter: Box<dyn Iterator<Item = Field>> = match fields {
540 Fields::Named(f) => Box::new(f.named.into_iter()),
541 Fields::Unnamed(f) => Box::new(f.unnamed.into_iter()),
542 Fields::Unit => Box::new(iter::empty()),
543 };
544 let fields_with_handling = fields_iter
545 .map(|field| {
546 let attrs = FieldHelperAttributes::from_attributes(&field.attrs)?;
547 let handling = if attrs.required.is_some() {
548 Required
549 } else if is_option(&field.ty) {
550 IsOption
551 } else {
552 Other
553 };
554 Ok::<_, Error>(FieldParsed { field, handling })
555 })
556 .collect::<Result<Vec<_>, _>>()?;
557
558 Ok(FieldsParsed {
559 struct_type: struct_named,
560 fields: fields_with_handling,
561 })
562}
563
564#[derive(Debug)]
567enum FieldHandling {
568 Required,
569 IsOption,
570 Other,
571}
572
573#[derive(Debug)]
575struct FieldParsed {
576 field: Field,
577 handling: FieldHandling,
578}
579
580#[derive(Debug, PartialEq)]
582enum StructType {
583 Named,
584 Unnamed,
585 Unit,
586}
587
588#[derive(Debug)]
590struct FieldsParsed {
591 struct_type: StructType,
592 fields: Vec<FieldParsed>,
593}
594
595fn is_option(ty: &Type) -> bool {
597 if let Type::Path(TypePath {
598 qself: _qself,
599 path,
600 }) = &ty
601 && {
602 let segments = &path.segments;
603 (segments.len() == 1 && segments[0].ident == "Option")
604 || (segments.len() == 2
605 && segments[0].ident == "option"
606 && segments[1].ident == "Option")
607 || (segments.len() == 3
608 && segments[0].ident == "std"
609 && segments[1].ident == "option"
610 && segments[2].ident == "Option")
611 }
612 {
613 true
614 } else {
615 false
616 }
617}
618
619fn is_serialize(path: &Path) -> bool {
621 path.is_ident("Serialize") || {
622 let segments = &path.segments;
623 segments.len() == 2 && segments[0].ident == "serde" && segments[1].ident == "Serialize"
624 }
625}
626
627fn optioned_ty(ty: &Type) -> TokenStream {
632 if is_self_resolving_optioned(ty) {
633 ty.to_token_stream()
634 } else {
635 quote! { <#ty as ::optionable::Optionable>::Optioned }
636 }
637}
638
639const SELF_RESOLVING_TYPES: [&str; 17] = [
640 "i8", "i16", "i32", "i64", "i128", "isize", "u8", "u16", "u32", "u64", "u128", "usize", "f32",
642 "f64", "char", "bool", "String",
644];
645
646fn is_self_resolving_optioned(ty: &Type) -> bool {
649 if let Type::Path(TypePath { qself, path }) = &ty
650 && qself.is_none()
651 && SELF_RESOLVING_TYPES.contains(&&*path.to_token_stream().to_string())
652 {
653 true
654 } else {
655 false
656 }
657}
658
659fn forwarded_attributes(attrs: &[Attribute]) -> Option<TokenStream> {
662 let forward_attrs = attrs
663 .iter()
664 .filter_map(|attr| {
665 if !attr.path().is_ident(HELPER_ATTR_IDENT) {
666 return None;
667 }
668 match &attr.meta {
669 Meta::List(l) => Some(l.tokens.clone()),
670 _ => None,
671 }
672 })
673 .collect::<Vec<_>>();
674 (!forward_attrs.is_empty()).then(|| quote!(#[#(#forward_attrs),*]))
675}
676
677pub(crate) fn error<S: AsRef<str> + fmt::Display, T>(msg: S) -> syn::Result<T> {
679 Err(Error::new(Span::call_site(), msg))
680}
681
682#[cfg(test)]
683mod tests {
684 use crate::derive_optionable;
685 use proc_macro2::TokenStream;
686 use quote::quote;
687
688 struct TestCase {
689 input: TokenStream,
690 output: TokenStream,
691 }
692
693 #[test]
694 #[allow(clippy::too_many_lines)]
695 fn test_optionable() {
696 let tcs = vec![
697 TestCase {
699 input: quote! {
700 #[derive(Optionable)]
701 struct DeriveExample {
702 name: String,
703 pub surname: String,
704 }
705 },
706 output: quote! {
707 #[automatically_derived]
708 struct DeriveExampleOpt {
709 name: Option<String>,
710 pub surname: Option<String>
711 }
712
713 #[automatically_derived]
714 impl ::optionable::Optionable for DeriveExample {
715 type Optioned = DeriveExampleOpt;
716 }
717
718 #[automatically_derived]
719 impl ::optionable::Optionable for DeriveExampleOpt {
720 type Optioned = DeriveExampleOpt;
721 }
722
723 #[automatically_derived]
724 impl ::optionable::OptionableConvert for DeriveExample {
725 fn into_optioned (self) -> DeriveExampleOpt {
726 DeriveExampleOpt {
727 name: Some(self.name),
728 surname:Some(self.surname)
729 }
730 }
731
732 fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::optionable::Error> {
733 Ok(Self{
734 name: value.name.ok_or(optionable::optionable::Error { missing_fields: std::vec!["name"] })?,
735 surname: value.surname.ok_or(optionable::optionable::Error { missing_fields: std::vec!["surname"] })?
736 })
737 }
738
739 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::optionable::Error> {
740 if let Some(other_value) = other.name {
741 self.name = other_value;
742 }
743 if let Some(other_value) = other.surname {
744 self.surname = other_value;
745 }
746 Ok(())
747 }
748 }
749 },
750 },
751 TestCase {
753 input: quote! {
754 #[derive(Optionable)]
755 #[optionable(no_convert)]
756 struct DeriveExample {
757 name: String,
758 pub surname: String,
759 }
760 },
761 output: quote! {
762 #[automatically_derived]
763 struct DeriveExampleOpt {
764 name: Option<String>,
765 pub surname: Option<String>
766 }
767
768 #[automatically_derived]
769 impl ::optionable::Optionable for DeriveExample {
770 type Optioned = DeriveExampleOpt;
771 }
772
773 #[automatically_derived]
774 impl ::optionable::Optionable for DeriveExampleOpt {
775 type Optioned = DeriveExampleOpt;
776 }
777 },
778 },
779 TestCase {
781 input: quote! {
782 #[derive(Optionable)]
783 struct DeriveExample {
784 name: String,
785 #[optionable(required)]
786 pub surname: String,
787 }
788 },
789 output: quote! {
790 #[automatically_derived]
791 struct DeriveExampleOpt {
792 name: Option<String>,
793 pub surname: String
794 }
795
796 #[automatically_derived]
797 impl ::optionable::Optionable for DeriveExample {
798 type Optioned = DeriveExampleOpt;
799 }
800
801 #[automatically_derived]
802 impl ::optionable::Optionable for DeriveExampleOpt {
803 type Optioned = DeriveExampleOpt;
804 }
805
806 #[automatically_derived]
807 impl ::optionable::OptionableConvert for DeriveExample {
808 fn into_optioned (self) -> DeriveExampleOpt {
809 DeriveExampleOpt {
810 name: Some(self.name),
811 surname: self.surname
812 }
813 }
814
815 fn try_from_optioned(value:DeriveExampleOpt ) -> Result <Self, ::optionable::optionable::Error> {
816 Ok (Self {
817 name: value.name.ok_or(optionable::optionable::Error { missing_fields: std::vec! ["name"] })?,
818 surname: value.surname
819 })
820 }
821
822 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::optionable::Error> {
823 if let Some(other_value) = other.name {
824 self.name = other_value;
825 }
826 self.surname = other.surname;
827 Ok (())
828 }
829 }
830 },
831 },
832 TestCase {
834 input: quote! {
835 #[derive(Optionable)]
836 #[optionable(derive(Deserialize,Serialize),suffix="Ac")]
837 #[optionable_attr(serde(rename_all = "camelCase"))]
838 struct DeriveExample {
839 #[optionable_attr(serde(rename = "firstName"))]
840 name: String,
841 middle_name: Option<String>,
842 surname: String,
843 }
844 },
845 output: quote! {
846 #[automatically_derived]
847 #[derive(Deserialize, Serialize)]
848 #[serde(rename_all = "camelCase")]
849 struct DeriveExampleAc {
850 #[serde(rename = "firstName")]
851 #[serde(skip_serializing_if = "Option::is_none")]
852 name: Option<String>,
853 #[serde(skip_serializing_if = "Option::is_none")]
854 middle_name: <Option<String> as ::optionable::Optionable>::Optioned,
855 #[serde(skip_serializing_if = "Option::is_none")]
856 surname: Option<String>
857 }
858
859 #[automatically_derived]
860 impl ::optionable::Optionable for DeriveExample {
861 type Optioned = DeriveExampleAc;
862 }
863
864 #[automatically_derived]
865 impl ::optionable::Optionable for DeriveExampleAc {
866 type Optioned = DeriveExampleAc;
867 }
868
869 #[automatically_derived]
870 impl ::optionable::OptionableConvert for DeriveExample {
871 fn into_optioned (self) -> DeriveExampleAc {
872 DeriveExampleAc {
873 name: Some(self.name),
874 middle_name: <Option<String> as ::optionable::OptionableConvert>::into_optioned(self.middle_name),
875 surname: Some(self.surname)
876 }
877 }
878
879 fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::optionable::Error> {
880 Ok(Self{
881 name: value.name.ok_or(optionable::optionable::Error { missing_fields: std::vec!["name"]})?,
882 middle_name: <Option<String> as ::optionable::OptionableConvert>::try_from_optioned(value.middle_name)?,
883 surname: value.surname.ok_or(optionable::optionable::Error { missing_fields: std::vec!["surname"]})?
884 })
885 }
886
887 fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::optionable::Error> {
888 if let Some(other_value) = other.name {
889 self.name = other_value;
890 }
891 <Option<String> as ::optionable::OptionableConvert>::merge(&mut self.middle_name, other.middle_name)?;
892 if let Some(other_value) = other.surname {
893 self.surname = other_value;
894 }
895 Ok(())
896 }
897 }
898 },
899 },
900 TestCase {
902 input: quote! {
903 #[derive(Optionable)]
904 #[optionable(derive(serde::Deserialize,serde::Serialize),suffix="Ac")]
905 struct DeriveExample {
906 name: String,
907 surname: String,
908 }
909 },
910 output: quote! {
911 #[automatically_derived]
912 #[derive(serde::Deserialize, serde::Serialize)]
913 struct DeriveExampleAc {
914 #[serde(skip_serializing_if = "Option::is_none")]
915 name: Option<String>,
916 #[serde(skip_serializing_if = "Option::is_none")]
917 surname: Option<String>
918 }
919
920 #[automatically_derived]
921 impl ::optionable::Optionable for DeriveExample {
922 type Optioned = DeriveExampleAc;
923 }
924
925 #[automatically_derived]
926 impl ::optionable::Optionable for DeriveExampleAc {
927 type Optioned = DeriveExampleAc;
928 }
929
930 #[automatically_derived]
931 impl ::optionable::OptionableConvert for DeriveExample {
932 fn into_optioned (self) -> DeriveExampleAc {
933 DeriveExampleAc {
934 name: Some(self.name),
935 surname: Some(self.surname)
936 }
937 }
938
939 fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::optionable::Error> {
940 Ok(Self{
941 name: value.name.ok_or(optionable::optionable::Error{ missing_fields: std::vec!["name"]})?,
942 surname: value.surname.ok_or(optionable::optionable::Error{ missing_fields: std::vec!["surname"]})?
943 })
944 }
945
946 fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::optionable::Error> {
947 if let Some(other_value) = other.name {
948 self.name = other_value;
949 }
950 if let Some(other_value) = other.surname {
951 self.surname = other_value;
952 }
953 Ok(())
954 }
955 }
956 },
957 },
958 TestCase {
960 input: quote! {
961 #[derive(Optionable)]
962 struct DeriveExample(pub String, i32);
963 },
964 output: quote! {
965 #[automatically_derived]
966 struct DeriveExampleOpt(
967 pub Option<String>,
968 Option<i32>
969 );
970
971 #[automatically_derived]
972 impl ::optionable::Optionable for DeriveExample {
973 type Optioned = DeriveExampleOpt;
974 }
975
976 #[automatically_derived]
977 impl ::optionable::Optionable for DeriveExampleOpt {
978 type Optioned = DeriveExampleOpt;
979 }
980
981 #[automatically_derived]
982 impl ::optionable::OptionableConvert for DeriveExample {
983 fn into_optioned (self) -> DeriveExampleOpt {
984 DeriveExampleOpt (
985 Some(self.0),
986 Some(self.1)
987 )
988 }
989
990 fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::optionable::Error> {
991 Ok(Self(
992 value.0.ok_or(optionable::optionable::Error { missing_fields: std::vec!["0"] })?,
993 value.1.ok_or(optionable::optionable::Error { missing_fields: std::vec!["1"] })?
994 ))
995 }
996
997 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::optionable::Error> {
998 if let Some(other_value) = other.0 {
999 self.0 = other_value;
1000 }
1001 if let Some (other_value) = other.1 {
1002 self.1 = other_value;
1003 }
1004 Ok (())
1005 }
1006 }
1007 },
1008 },
1009 TestCase {
1011 input: quote! {
1012 #[derive(Optionable)]
1013 struct DeriveExample(pub String, #[optionable(required)] i32);
1014 },
1015 output: quote! {
1016 #[automatically_derived]
1017 struct DeriveExampleOpt(
1018 pub Option<String>,
1019 i32
1020 );
1021
1022 #[automatically_derived]
1023 impl ::optionable::Optionable for DeriveExample {
1024 type Optioned = DeriveExampleOpt;
1025 }
1026
1027 #[automatically_derived]
1028 impl ::optionable::Optionable for DeriveExampleOpt {
1029 type Optioned = DeriveExampleOpt;
1030 }
1031
1032 # [automatically_derived]
1033 impl ::optionable::OptionableConvert for DeriveExample {
1034 fn into_optioned (self) -> DeriveExampleOpt {
1035 DeriveExampleOpt (
1036 Some(self.0),
1037 self.1
1038 )
1039 }
1040
1041 fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::optionable::Error> {
1042 Ok(Self(
1043 value.0.ok_or(optionable::optionable::Error { missing_fields: std::vec!["0"] })?,
1044 value.1))
1045 }
1046
1047 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::optionable::Error> {
1048 if let Some(other_value) = other.0 {
1049 self.0 = other_value;
1050 }
1051 self.1 = other.1;
1052 Ok (())
1053 }
1054 }
1055 },
1056 },
1057 TestCase {
1059 input: quote! {
1060 #[derive(Optionable)]
1061 struct DeriveExample<T, T2: Serialize> where T: DeserializeOwned {
1062 output: T,
1063 input: T2,
1064 }
1065 },
1066 output: quote! {
1067 #[automatically_derived]
1068 struct DeriveExampleOpt<T, T2: Serialize>
1069 where T: DeserializeOwned + ::optionable::Optionable,
1070 T2: ::optionable::Optionable {
1071 output: Option< <T as ::optionable::Optionable>::Optioned>,
1072 input: Option< <T2 as ::optionable::Optionable>::Optioned>
1073 }
1074
1075 #[automatically_derived]
1076 impl<T, T2: Serialize> ::optionable::Optionable for DeriveExample<T, T2>
1077 where T: DeserializeOwned + ::optionable::Optionable,
1078 T2: ::optionable::Optionable {
1079 type Optioned = DeriveExampleOpt<T,T2>;
1080 }
1081
1082 #[automatically_derived]
1083 impl<T, T2: Serialize> ::optionable::Optionable for DeriveExampleOpt<T, T2>
1084 where T: DeserializeOwned + ::optionable::Optionable,
1085 T2: ::optionable::Optionable {
1086 type Optioned = DeriveExampleOpt<T,T2>;
1087 }
1088
1089 #[automatically_derived]
1090 impl <T, T2:Serialize> ::optionable::OptionableConvert for DeriveExample<T, T2 >
1091 where T: DeserializeOwned + ::optionable::OptionableConvert,
1092 T2: ::optionable::OptionableConvert {
1093 fn into_optioned (self) -> DeriveExampleOpt<T, T2> {
1094 DeriveExampleOpt::<T, T2> {
1095 output: Some(<T as::optionable::OptionableConvert>::into_optioned(self.output)),
1096 input: Some(<T2 as::optionable::OptionableConvert>::into_optioned(self.input))
1097 }
1098 }
1099
1100 fn try_from_optioned(value: DeriveExampleOpt<T, T2> ) -> Result <Self, ::optionable::optionable::Error> {
1101 Ok(Self{
1102 output: <T as ::optionable::OptionableConvert>::try_from_optioned(value.output.ok_or(optionable::optionable::Error { missing_fields: std::vec!["output"] })?)?,
1103 input: <T2 as ::optionable::OptionableConvert>::try_from_optioned(value.input.ok_or(optionable::optionable::Error { missing_fields: std::vec!["input"] })?)?
1104 })
1105 }
1106
1107 fn merge(&mut self, other: DeriveExampleOpt<T, T2> ) -> Result<(), ::optionable::optionable::Error> {
1108 if let Some(other_value) = other.output {
1109 <T as ::optionable::OptionableConvert>::merge(&mut self.output, other_value)?;
1110 }
1111 if let Some(other_value) = other.input {
1112 <T2 as ::optionable::OptionableConvert>::merge(&mut self.input, other_value)?;
1113 }
1114 Ok(())
1115 }
1116 }
1117 },
1118 },
1119 TestCase {
1120 input: quote! {
1121 #[derive(Optionable)]
1122 enum DeriveExample {
1123 Unit,
1124 Plain(String),
1125 Address{street: String, number: u32},
1126 Address2(String,u32),
1127 }
1128 },
1129 output: quote! {
1130 # [automatically_derived]
1131 enum DeriveExampleOpt {
1132 Unit,
1133 Plain( Option<String> ),
1134 Address{ street: Option<String>, number:Option<u32> },
1135 Address2( Option<String>, Option<u32> )
1136 }
1137
1138 #[automatically_derived]
1139 impl ::optionable::Optionable for DeriveExample {
1140 type Optioned = DeriveExampleOpt;
1141 }
1142
1143 #[automatically_derived]
1144 impl ::optionable::Optionable for DeriveExampleOpt {
1145 type Optioned = DeriveExampleOpt;
1146 }
1147
1148 #[automatically_derived]
1149 impl ::optionable::OptionableConvert for DeriveExample {
1150 fn into_optioned (self) -> DeriveExampleOpt {
1151 match self{
1152 Self::Unit => DeriveExampleOpt::Unit,
1153 Self::Plain(self_0) => DeriveExampleOpt::Plain(
1154 Some(self_0)
1155 ),
1156 Self::Address{street: self_street, number: self_number} => DeriveExampleOpt::Address{
1157 street: Some(self_street),
1158 number: Some(self_number)
1159 },
1160 Self::Address2(self_0, self_1) => DeriveExampleOpt::Address2(
1161 Some(self_0),
1162 Some(self_1)
1163 )
1164 }
1165 }
1166
1167 fn try_from_optioned(other: DeriveExampleOpt) -> Result <Self, ::optionable::optionable::Error> {
1168 Ok (match other {
1169 DeriveExampleOpt::Unit => Self::Unit,
1170 DeriveExampleOpt::Plain(other_0) => Self::Plain(
1171 other_0.ok_or(optionable::optionable::Error { missing_fields: std::vec!["0"] })?
1172 ),
1173 DeriveExampleOpt::Address{street: other_street, number: other_number} => Self::Address{
1174 street: other_street.ok_or(optionable::optionable::Error { missing_fields: std::vec!["street"] })?,
1175 number: other_number.ok_or(optionable::optionable::Error { missing_fields: std::vec!["number"] })?
1176 },
1177 DeriveExampleOpt::Address2(other_0, other_1) => Self::Address2(
1178 other_0.ok_or(optionable::optionable::Error { missing_fields: std::vec!["0"] })?,
1179 other_1.ok_or(optionable::optionable::Error { missing_fields: std::vec! ["1"] })?)
1180 })
1181 }
1182
1183 fn merge(&mut self, other: DeriveExampleOpt) -> Result<(), ::optionable::optionable::Error> {
1184 match other {
1185 DeriveExampleOpt::Unit => {
1186 if let Self::Unit = self {} else {
1187 *self = Self::try_from_optioned(DeriveExampleOpt::Unit)?;
1188 }
1189 },
1190 DeriveExampleOpt::Plain(other_0) => {
1191 if let Self::Plain(self_0) = self{
1192 if let Some(other_value) = other_0 {
1193 *self_0 = other_value;
1194 }
1195 } else {
1196 *self = Self::try_from_optioned(DeriveExampleOpt::Plain(other_0))?;
1197 }
1198 },
1199 DeriveExampleOpt::Address{street: other_street, number: other_number} => {
1200 if let Self::Address{street: self_street, number: self_number} = self{
1201 if let Some(other_value) = other_street {
1202 *self_street = other_value;
1203 }
1204 if let Some(other_value) = other_number {
1205 *self_number = other_value;
1206 }
1207 } else {
1208 *self = Self::try_from_optioned(DeriveExampleOpt::Address{street: other_street, number: other_number})?;
1209 }
1210 },
1211 DeriveExampleOpt::Address2(other_0, other_1) => {
1212 if let Self::Address2(self_0, self_1) = self{
1213 if let Some(other_value) = other_0 {
1214 *self_0 = other_value;
1215 }
1216 if let Some(other_value) = other_1 {
1217 *self_1 = other_value;
1218 }
1219 } else {
1220 *self = Self::try_from_optioned(DeriveExampleOpt::Address2(other_0, other_1))?;
1221 }
1222 }
1223 }
1224 Ok(())
1225 }
1226 }
1227 },
1228 },
1229 ];
1230 for tc in tcs {
1231 let input = syn::parse2(tc.input).unwrap();
1232 let output = derive_optionable(input).unwrap();
1233 println!("{output}");
1234 assert_eq!(tc.output.to_string(), output.to_string());
1235 }
1236 }
1237}