1mod helper;
14mod k8s_openapi;
15mod parsed_input;
16mod where_clause;
17
18use crate::helper::{destructure, error, error_on_helper_attributes, is_serialize, struct_wrapper};
19use crate::k8s_openapi::{
20 error_missing_features, k8s_adjust_fields, k8s_derives, k8s_openapi_impl_metadata,
21 k8s_openapi_impl_resource, k8s_resource_type, k8s_type_attr,
22};
23use crate::parsed_input::{
24 into_field_handling, FieldHandling, FieldParsed, StructParsed, StructType,
25};
26use crate::where_clause::{where_clauses, WhereClauses};
27use darling::util::PathList;
28use darling::{FromAttributes, FromDeriveInput, FromMeta};
29use itertools::MultiUnzip;
30use proc_macro2::{Ident, Literal, TokenStream};
31use quote::{format_ident, quote, ToTokens};
32use std::borrow::Cow;
33use std::collections::{BTreeSet, HashMap, HashSet};
34use std::default::Default;
35use std::mem::take;
36use syn::parse::Parser;
37use syn::punctuated::Punctuated;
38use syn::spanned::Spanned;
39use syn::{
40 parse_quote, Attribute, Data, DeriveInput, Error, Field, Fields, LitStr, Meta, MetaList, Path, Token,
41 Type, TypePath, WhereClause,
42};
43
44const HELPER_IDENT: &str = "optionable";
45const HELPER_ATTR_IDENT: &str = "optionable_attr";
46const ERR_MSG_HELPER_ATTR_ENUM_VARIANTS: &str =
47 "#[optionable] helper attributes not supported on enum variant level.";
48
49#[derive(FromDeriveInput)]
50#[darling(attributes(optionable))]
51pub(crate) struct TypeHelperAttributes {
53 #[darling(multiple)]
57 attr_copy: Vec<FieldAttributeToCopy>,
58 #[darling(multiple)]
60 derive: Vec<PathList>,
61 suffix: Option<LitStr>,
63 no_convert: Option<()>,
65 k8s_openapi: Option<TypeHelperAttributesK8sOpenapi>,
69 kube: Option<TypeHelperAttributesKube>,
74}
75
76#[derive(FromMeta)]
77pub(crate) struct TypeHelperAttributesK8sOpenapi {
82 metadata: Option<()>,
86 resource: Option<()>,
90}
91
92#[derive(FromMeta)]
93pub(crate) struct TypeHelperAttributesKube {
96 resource: Option<()>,
101}
102
103#[derive(FromMeta)]
104pub struct FieldAttributeToCopy {
108 pub attr: Path,
109 pub key: Option<Path>,
110}
111
112#[derive(FromDeriveInput, Debug, Clone)]
113#[darling(attributes(optionable))]
114pub struct CodegenSettings {
118 pub optionable_crate_name: Path,
122 pub ty_prefix: Option<Path>,
125 pub input_crate_replacement: Option<Ident>,
129}
130
131fn field_attr_copy_hashmap(
134 input: Vec<FieldAttributeToCopy>,
135 attr_kube: Option<&TypeHelperAttributesKube>,
136) -> HashMap<Path, HashSet<Path>> {
137 let mut result = HashMap::<Path, HashSet<Path>>::new();
138 for el in input {
139 if let Some(key) = el.key {
140 if let Some(entry) = result.get_mut(&el.attr) {
141 entry.insert(key);
142 } else {
143 result.insert(el.attr, HashSet::from([key]));
144 }
145 }
146 }
147 if attr_kube.is_some() {
148 let path_serde = Path::from_string("serde").unwrap();
149 let path_rename = Path::from_string("rename").unwrap();
150 let path_rename_all = Path::from_string("rename_all").unwrap();
151 let path_rename_all_fields = Path::from_string("rename_all_fields").unwrap();
152 if let Some(entry) = result.get_mut(&path_serde) {
153 if !entry.is_empty() {
155 entry.insert(path_rename);
156 entry.insert(path_rename_all);
157 }
158 } else {
159 result.insert(
160 path_serde,
161 HashSet::from([path_rename, path_rename_all, path_rename_all_fields]),
162 );
163 }
164 }
165 result
166}
167
168impl Default for CodegenSettings {
169 fn default() -> Self {
170 Self {
171 optionable_crate_name: parse_quote!(::optionable),
172 ty_prefix: None,
173 input_crate_replacement: None,
174 }
175 }
176}
177
178#[derive(FromAttributes)]
179#[darling(attributes(optionable))]
180struct FieldHelperAttributes {
182 required: Option<()>,
184 #[darling(rename = "optioned_type")]
187 optioned_ty: Option<Path>,
188}
189
190#[must_use]
192pub fn attribute_no_convert() -> Attribute {
193 parse_quote!(#[optionable(no_convert)])
194}
195
196#[must_use]
198pub fn attribute_suffix(suffix: &str) -> Attribute {
199 parse_quote!(#[optionable(suffix=#suffix)])
200}
201
202#[must_use]
205pub fn attribute_derives(derives: &PathList) -> Attribute {
206 parse_quote!(#[optionable(derive(#(#derives),*))])
207}
208
209#[allow(clippy::too_many_lines)]
215#[allow(clippy::items_after_statements)]
216pub fn derive_optionable(
217 input: DeriveInput,
218 settings: Option<&CodegenSettings>,
219) -> syn::Result<TokenStream> {
220 let settings = settings.map(Cow::Borrowed).unwrap_or_default();
221 let crate_name = &settings.optionable_crate_name;
222 let TypeHelperAttributes {
223 attr_copy,
224 derive: attr_derive,
225 suffix: attr_suffix,
226 no_convert: attr_no_convert,
227 k8s_openapi: attr_k8s_openapi,
228 kube: attr_kube,
229 } = TypeHelperAttributes::from_derive_input(&input)?;
230 let DeriveInput {
231 attrs,
232 vis,
233 mut generics,
234 data,
235 ..
236 } = input;
237 error_missing_features(attr_k8s_openapi.as_ref(), attr_kube.as_ref())?;
238
239 let ty_ident_opt = {
240 let suffix = attr_suffix.map_or_else(
241 || {
242 if attr_kube.is_some() || attr_k8s_openapi.is_some() {
243 Cow::Borrowed("Ac")
244 } else {
245 Cow::Borrowed("Opt")
246 }
247 },
248 |s| Cow::Owned(s.value()),
249 );
250 Ident::new(&(input.ident.to_string() + &suffix), input.ident.span())
251 };
252 let ty_ident = if let Some(mut ty_prefix) = settings.ty_prefix.clone() {
253 ty_prefix.segments.push(input.ident.into());
254 ty_prefix
255 } else {
256 input.ident.into()
257 };
258 if let Data::Enum(e) = &data
259 && e.variants
260 .iter()
261 .all(|el| matches!(el.fields, Fields::Unit))
262 {
263 return Ok(impl_optionable_self(
265 crate_name,
266 &ty_ident,
267 attr_no_convert.is_some(),
268 ));
269 }
270
271 let k8s_resource_type = k8s_resource_type(attr_k8s_openapi.as_ref(), attr_kube.as_ref())?;
272 let k8s_openapi_attrs = attr_k8s_openapi.is_some().then(|| k8s_type_attr(&data));
273 let attr_copy_identifier = field_attr_copy_hashmap(attr_copy, attr_kube.as_ref());
274 let ty_attr_forwarded = forwarded_attributes(&attrs, &attr_copy_identifier)?;
275
276 let mut derive = attr_derive
277 .into_iter()
278 .flat_map(|el| {
279 el.iter()
280 .map(|el| el.to_token_stream().to_string())
281 .collect::<Vec<_>>()
282 })
283 .collect::<BTreeSet<_>>();
284 if (attr_k8s_openapi.is_some() || attr_kube.is_some())
285 && let Some(k8s_derives) = k8s_derives(&data)
286 {
287 for el in k8s_derives {
288 derive.insert(el);
289 }
290 }
291
292 let vis = vis;
293 let where_clause = take(&mut generics.where_clause);
295 let (impl_generics, ty_generics, _) = generics.split_for_impl();
296 let generics_colon = (!generics.params.is_empty()).then(|| quote! {::});
297 let skip_optionable_if_serde_serialize =
298 (attr_k8s_openapi.is_some() || derive.iter().any(|el| is_serialize(el.as_str())))
300 .then(|| quote!(#[serde(skip_serializing_if = "Option::is_none")]));
301
302 struct Derived {
304 enum_struct: TokenStream,
306 fields: TokenStream,
308 where_clause_struct_enum: WhereClause,
310 where_clause_impl_optionable: WhereClause,
312 where_clause_impl_optionable_convert: Option<WhereClause>,
314 impl_optionable_convert: Option<TokenStream>,
316 }
317 let Derived {
318 enum_struct,
319 fields,
320 where_clause_struct_enum,
321 where_clause_impl_optionable,
322 where_clause_impl_optionable_convert,
323 impl_optionable_convert,
324 } = match data {
325 Data::Struct(s) => {
326 let mut struct_parsed = into_field_handling(
327 crate_name.to_owned(),
328 s.fields,
329 settings.input_crate_replacement.as_ref(),
330 )?;
331 k8s_adjust_fields(
332 &mut struct_parsed,
333 attr_k8s_openapi.as_ref(),
334 attr_kube.as_ref(),
335 k8s_resource_type.as_ref(),
336 crate_name,
337 )?;
338 let WhereClauses {
339 struct_enum_def: where_clause_struct_enum,
340 impl_optionable: where_clause_impl_optionable,
341 impl_optionable_convert: where_clause_impl_optionable_convert,
342 } = where_clauses(
343 where_clause,
344 &generics.params,
345 crate_name,
346 settings.input_crate_replacement.as_ref(),
347 &derive,
348 attr_no_convert.is_some(),
349 &struct_parsed.fields,
350 )?;
351 let unnamed_struct_semicolon =
352 (struct_parsed.struct_type == StructType::Unnamed).then(|| quote!(;));
353 let optioned_fields = optioned_fields(
354 &struct_parsed,
355 skip_optionable_if_serde_serialize.as_ref(),
356 &attr_copy_identifier,
357 )?;
358
359 let impl_optionable_convert = attr_no_convert.is_none().then(|| {
360 let into_optioned_fields = into_optioned(&struct_parsed, |selector| quote! { self.#selector });
361 let try_from_optioned_fields =
362 try_from_optioned(&struct_parsed, |selector| quote! { value.#selector });
363 let merge_fields = merge_fields(
364 &struct_parsed,
365 |selector| quote! { self.#selector },
366 |selector| quote! { other.#selector },
367 true);
368 quote! {
369 #[automatically_derived]
370 impl #impl_generics #crate_name::OptionableConvert for #ty_ident #ty_generics #where_clause_impl_optionable_convert{
371 fn into_optioned(self) -> #ty_ident_opt #ty_generics {
372 #ty_ident_opt #generics_colon #ty_generics #into_optioned_fields
373 }
374
375 fn try_from_optioned(value: #ty_ident_opt #ty_generics) -> Result<Self, #crate_name::Error>{
376 Ok(Self #try_from_optioned_fields)
377 }
378
379 fn merge(&mut self, other: #ty_ident_opt #ty_generics) -> Result<(), #crate_name::Error>{
380 #merge_fields
381 Ok(())
382 }
383 }
384 }
385 });
386 Derived {
387 enum_struct: quote! {struct},
388 fields: quote! {#optioned_fields #unnamed_struct_semicolon},
389 where_clause_struct_enum,
390 where_clause_impl_optionable,
391 where_clause_impl_optionable_convert,
392 impl_optionable_convert,
393 }
394 }
395 Data::Enum(e) => {
396 let self_prefix = quote! {self_};
397 let other_prefix = quote! {other_};
398
399 let variants = e
400 .variants
401 .into_iter()
402 .map(|v| {
403 error_on_helper_attributes(&v.attrs, ERR_MSG_HELPER_ATTR_ENUM_VARIANTS)?;
404 let mut field_handling = into_field_handling(
405 crate_name.to_owned(),
406 v.fields,
407 settings.input_crate_replacement.as_ref(),
408 )?;
409 k8s_adjust_fields(
410 &mut field_handling,
411 attr_k8s_openapi.as_ref(),
412 attr_kube.as_ref(),
413 k8s_resource_type.as_ref(),
414 crate_name,
415 )?;
416 Ok::<_, Error>((
417 v.ident,
418 forwarded_attributes(&v.attrs, &attr_copy_identifier)?,
419 field_handling,
420 ))
421 })
422 .collect::<Result<Vec<_>, _>>()?;
423 let all_fields = variants
424 .iter()
425 .flat_map(|(_, _, fields)| &fields.fields)
426 .collect::<Vec<_>>();
427 let WhereClauses {
428 struct_enum_def: where_clause_struct_enum,
429 impl_optionable: where_clause_impl_optionable,
430 impl_optionable_convert: where_clause_impl_optionable_convert,
431 } = where_clauses(
432 where_clause,
433 &generics.params,
434 crate_name,
435 settings.input_crate_replacement.as_ref(),
436 &derive,
437 attr_no_convert.is_some(),
438 all_fields,
439 )?;
440
441 let optioned_variants = variants
442 .iter()
443 .map(|(variant, forward_attrs, f)| {
444 let fields = optioned_fields(
445 f,
446 skip_optionable_if_serde_serialize.as_ref(),
447 &attr_copy_identifier,
448 )?;
449 Ok::<_, Error>(quote!( #forward_attrs #variant #fields ))
450 })
451 .collect::<Result<Vec<_>, _>>()?;
452
453 let impl_optionable_convert = attr_no_convert.is_none().then(|| {
454 let (into_variants, try_from_variants, merge_variants): (Vec<_>, Vec<_>, Vec<_>) = variants
455 .iter()
456 .map(|(variant, _, struct_parsed)| {
457 let fields_into = into_optioned(struct_parsed, |selector| {
458 format_ident!("{self_prefix}{selector}").to_token_stream()
459 });
460 let fields_try_from = try_from_optioned
461 (struct_parsed, |selector| {
462 format_ident!("{other_prefix}{selector}").to_token_stream()
463 });
464 let fields_merge = merge_fields(struct_parsed,
465 |selector| format_ident!("{self_prefix}{selector}").to_token_stream(),
466 |selector| format_ident!("{other_prefix}{selector}").to_token_stream(),
467 false);
468 let self_destructure = destructure(struct_parsed, &self_prefix)?;
469 let other_destructure = destructure(struct_parsed, &other_prefix)?;
470 Ok::<_, Error>((
471 quote!( Self::#variant #self_destructure => #ty_ident_opt::#variant #fields_into ),
472 quote!( #ty_ident_opt::#variant #other_destructure => Self::#variant #fields_try_from ),
473 quote!( #ty_ident_opt::#variant #other_destructure => {
474 if let Self::#variant #self_destructure = self {
475 #fields_merge
476 } else {
477 *self = Self::try_from_optioned(#ty_ident_opt::#variant #other_destructure)?;
478 }
479 })
480 ))
481 })
482 .collect::<Result<Vec<_>, _>>()?
483 .into_iter().multiunzip();
484 Ok::<_, Error>(quote! {
485 #[automatically_derived]
486 impl #impl_generics #crate_name::OptionableConvert for #ty_ident #ty_generics #where_clause_impl_optionable_convert {
487 fn into_optioned(self) -> #ty_ident_opt #ty_generics {
488 match self {
489 #(#into_variants),*
490 }
491 }
492
493 fn try_from_optioned(other: #ty_ident_opt #ty_generics)->Result<Self,#crate_name::Error>{
494 Ok(match other{
495 #(#try_from_variants),*
496 })
497 }
498
499 fn merge(&mut self, other: #ty_ident_opt #ty_generics) -> Result<(), #crate_name::Error>{
500 match other{
501 #(#merge_variants),*
502 }
503 Ok(())
504 }
505 }
506 })
507 }).transpose()?;
508 Derived {
509 enum_struct: quote! {enum},
510 fields: quote! {{#(#optioned_variants),*}},
511 where_clause_struct_enum,
512 where_clause_impl_optionable,
513 where_clause_impl_optionable_convert,
514 impl_optionable_convert,
515 }
516 }
517 Data::Union(_) => return error("#[derive(Optionable)] not supported for unit structs"),
518 };
519 let impl_optioned_convert = attr_no_convert.is_none().then(|| {
520 quote! {
521 #[automatically_derived]
522 impl #impl_generics #crate_name::OptionedConvert<#ty_ident #ty_generics> for #ty_ident_opt #ty_generics #where_clause_impl_optionable_convert {
523 fn from_optionable(value: #ty_ident #ty_generics) -> Self {
524 #crate_name::OptionableConvert::into_optioned(value)
525 }
526 fn try_into_optionable(self) -> Result<#ty_ident #ty_generics, #crate_name::Error> {
527 #crate_name::OptionableConvert::try_from_optioned(self)
528 }
529 fn merge_into(self, other: &mut #ty_ident #ty_generics) -> Result<(), #crate_name::Error> {
530 #crate_name::OptionableConvert::merge(other, self)
531 }
532 }
533 }
534 });
535
536 let derive = derive
537 .into_iter()
538 .map(|derive| Path::from_string(&derive))
539 .collect::<Result<Vec<_>, _>>()?;
540 let derive = (!derive.is_empty()).then(|| quote! {#[derive(#(#derive),*)]});
541
542 let k8s_openapi_impl_resource = attr_k8s_openapi
543 .as_ref()
544 .is_some_and(|attr| attr.resource.is_some())
545 .then(|| {
546 k8s_openapi_impl_resource(
547 &ty_ident,
548 &ty_ident_opt,
549 &impl_generics,
550 &ty_generics,
551 &where_clause_impl_optionable,
552 )
553 });
554 let impl_k8s_metadata = attr_k8s_openapi
555 .as_ref()
556 .is_some_and(|attr| attr.metadata.is_some())
557 .then(|| {
558 k8s_openapi_impl_metadata(
559 &ty_ident,
560 &ty_ident_opt,
561 &impl_generics,
562 &ty_generics,
563 &where_clause_impl_optionable,
564 )
565 });
566 let kube_derive_resource = attr_kube
567 .is_some_and(|attr| attr.resource.is_some())
568 .then(|| {
569 quote! {
570 #[derive(kube::Resource)]
571 #[resource(inherit = #ty_ident )]
572 }
573 });
574 let k8s_roundtrip_test = (attr_k8s_openapi.is_some_and(|attr|attr.resource.is_some())
575 && ty_generics.to_token_stream().is_empty()
576 && ty_ident_opt!="CustomResourceDefinitionAc"
580 && ty_ident_opt!="StorageVersionAc"
582 && ty_ident_opt!="DeviceClassAc"
583 && ty_ident_opt!="ResourceClaimAc"
584 && ty_ident_opt!="ResourceClaimTemplateAc")
585 .then(|| {
586 let fn_name = Ident::from_string(
587 &("roundtrip_".to_owned()
588 + &ty_ident_opt.to_token_stream().to_string().to_lowercase()),
589 )?;
590 Ok::<_, Error>(quote! {
591 #[cfg(test_k8s_openapi_roundtrip)]
592 #[test]
593 fn #fn_name() {
594 crate::testutil::roundtrip_test::<#ty_ident>();
595 }
596 })
597 })
598 .transpose()?;
599 Ok(quote! {
600 #derive
601 #kube_derive_resource
602 #ty_attr_forwarded
603 #k8s_openapi_attrs
604 #vis #enum_struct #ty_ident_opt #impl_generics #where_clause_struct_enum #fields
605
606 #[automatically_derived]
607 impl #impl_generics #crate_name::Optionable for #ty_ident #ty_generics #where_clause_impl_optionable {
608 type Optioned = #ty_ident_opt #ty_generics;
609 }
610
611 #[automatically_derived]
612 impl #impl_generics #crate_name::Optionable for #ty_ident_opt #ty_generics #where_clause_impl_optionable {
613 type Optioned = #ty_ident_opt #ty_generics;
614 }
615
616 #impl_optionable_convert
617 #impl_optioned_convert
618
619 #k8s_openapi_impl_resource
620 #impl_k8s_metadata
621
622 #k8s_roundtrip_test
623 })
624}
625
626fn impl_optionable_self(crate_name: &Path, ty_ident: &Path, no_convert: bool) -> TokenStream {
628 let convert_impl = (!no_convert).then(|| {
629 quote! {
630 #[automatically_derived]
631 impl #crate_name::OptionableConvert for #ty_ident{
632 fn into_optioned(self) -> #ty_ident {
633 self
634 }
635
636 fn try_from_optioned(value: Self::Optioned) -> Result<Self, #crate_name::Error> {
637 Ok(value)
638 }
639
640 fn merge(&mut self, other: Self::Optioned) -> Result<(), #crate_name::Error> {
641 *self = other;
642 Ok(())
643 }
644 }
645 }
646 });
647 quote! {
648 #[automatically_derived]
649 impl #crate_name::Optionable for #ty_ident{
650 type Optioned = Self;
651 }
652
653 #convert_impl
654 }
655}
656
657fn optioned_fields(
661 fields: &StructParsed,
662 serde_attributes: Option<&TokenStream>,
663 field_attr_forwards: &HashMap<Path, HashSet<Path>>,
664) -> Result<TokenStream, Error> {
665 let fields_token = fields.fields.iter().map(
666 |FieldParsed {
667 field: Field { attrs, vis, ident, ty, .. },
668 handling,
669 }| {
670 let forwarded_attrs = forwarded_attributes(attrs, field_attr_forwards)?;
671 let optioned_ty = optioned_ty(&fields.crate_name, ty);
672 let colon = ident.as_ref().map(|_| quote! {:});
673 Ok::<_, Error>(match handling {
674 FieldHandling::Required | FieldHandling::OptionedOnly => quote! {#forwarded_attrs #vis #ident #colon #ty},
675 FieldHandling::ManualOptioned(ty_opt) => quote! {#forwarded_attrs #vis #ident #colon Option<#ty_opt>},
676 FieldHandling::IsOption => quote! {#forwarded_attrs #serde_attributes #vis #ident #colon #optioned_ty},
677 FieldHandling::Other => quote! {#forwarded_attrs #serde_attributes #vis #ident #colon Option<#optioned_ty>},
678 })
679 },
680 ).collect::<Result<Vec<_>, _>>()?;
681 Ok(struct_wrapper(fields_token, &fields.struct_type))
682}
683
684fn into_optioned(
688 struct_parsed: &StructParsed,
689 self_selector_fn: impl Fn(&TokenStream) -> TokenStream,
690) -> TokenStream {
691 let fields_token = struct_parsed.fields.iter().enumerate().map(|(i, FieldParsed { field: Field { ident, ty, .. }, handling })| {
692 let colon = ident.as_ref().map(|_| quote! {:});
693 let selector = ident.as_ref().map_or_else(|| {
694 let i = Literal::usize_unsuffixed(i);
695 quote! {#i}
696 }, ToTokens::to_token_stream);
697 let self_selector = self_selector_fn(&selector);
698 let crate_name = &struct_parsed.crate_name;
699 match (handling, is_self_resolving_optioned(ty)) {
700 (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => quote! {#ident #colon #self_selector},
701 (FieldHandling::ManualOptioned(_), _) => quote! {#ident #colon Some(#crate_name::OptionedConvert::from_optionable(#self_selector))},
702 (FieldHandling::IsOption, false) => quote! {#ident #colon #crate_name::OptionableConvert::into_optioned(#self_selector)},
703 (FieldHandling::Other, true) => quote! {#ident #colon Some(#self_selector)},
704 (FieldHandling::Other, false) => quote! {#ident #colon Some(#crate_name::OptionableConvert::into_optioned(#self_selector))},
705 (FieldHandling::OptionedOnly, _) => quote! {#ident #colon Default::default()},
706 }
707 });
708 struct_wrapper(fields_token, &struct_parsed.struct_type)
709}
710
711fn try_from_optioned(
715 struct_parsed: &StructParsed,
716 value_selector_fn: impl Fn(&TokenStream) -> TokenStream,
717) -> TokenStream {
718 let fields_token = struct_parsed.fields.iter().enumerate().filter_map(|(i, FieldParsed { field: Field { ident, ty, .. }, handling })| {
719 let colon = ident.as_ref().map(|_| quote! {:});
720 let selector = ident.as_ref().map_or_else(|| {
721 let i = Literal::usize_unsuffixed(i);
722 quote! {#i}
723 }, ToTokens::to_token_stream);
724 let value_selector = value_selector_fn(&selector);
725 let crate_name = &struct_parsed.crate_name;
726 match (handling, is_self_resolving_optioned(ty)) {
727 (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => Some(quote! {#ident #colon value.#selector}),
728 (FieldHandling::ManualOptioned(_), _) => {
729 let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
730 Some(quote! {
731 #ident #colon #crate_name::OptionedConvert::try_into_optionable(#value_selector.ok_or(#crate_name::Error{ missing_field: #selector_quoted })?
732 )?
733 })
734 }
735 (FieldHandling::IsOption, false) => Some(quote! {
736 #ident #colon #crate_name::OptionableConvert::try_from_optioned(
737 #value_selector
738 )?
739 }),
740 (FieldHandling::Other, true) => {
741 let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
742 Some(quote! {
743 #ident #colon #value_selector.ok_or(#crate_name::Error{ missing_field: #selector_quoted })?
744 })
745 }
746 (FieldHandling::Other, false) => {
747 let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
748 Some(quote! {
749 #ident #colon #crate_name::OptionableConvert::try_from_optioned(#value_selector.ok_or(#crate_name::Error{ missing_field: #selector_quoted })?
750 )?
751 })
752 }
753 (FieldHandling::OptionedOnly, _) => None,
754 }
755 });
756
757 struct_wrapper(fields_token, &struct_parsed.struct_type)
758}
759
760fn merge_fields(
766 struct_parsed: &StructParsed,
767 self_selector_fn: impl Fn(&TokenStream) -> TokenStream,
768 other_selector_fn: impl Fn(&TokenStream) -> TokenStream,
769 merge_self_mut: bool,
770) -> TokenStream {
771 let fields_token = struct_parsed.fields.iter().enumerate().filter_map(
772 |(
773 i,
774 FieldParsed {
775 field: Field { ident, ty, .. },
776 handling,
777 },
778 )| {
779 let selector = ident.as_ref().map_or_else(
780 || {
781 let i = Literal::usize_unsuffixed(i);
782 quote! {#i}
783 },
784 ToTokens::to_token_stream,
785 );
786 let self_merge_mut_modifier = merge_self_mut.then(|| quote! {&mut});
787 let deref_modifier = (!merge_self_mut).then(|| quote! {*});
788 let self_selector = self_selector_fn(&selector);
789 let other_selector = other_selector_fn(&selector);
790 let crate_name = &struct_parsed.crate_name;
791 match (handling, is_self_resolving_optioned(ty)) {
792 (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => Some(quote! {#deref_modifier #self_selector = #other_selector;}),
793 (FieldHandling::ManualOptioned(_), _) => Some(quote! {
794 if let Some(other_value)=#other_selector{
795 #crate_name::OptionedConvert::merge_into(other_value, #self_merge_mut_modifier #self_selector)?;
796 }
797 }),
798 (FieldHandling::IsOption, false) => Some(quote! {
799 #crate_name::OptionableConvert::merge(#self_merge_mut_modifier #self_selector, #other_selector)?;
800 }),
801 (FieldHandling::Other, true) => Some(quote! {
802 if let Some(other_value)=#other_selector{
803 #deref_modifier #self_selector = other_value;
804 }
805 }),
806 (FieldHandling::Other, false) => Some(quote! {
807 if let Some(other_value)=#other_selector{
808 #crate_name::OptionableConvert::merge(#self_merge_mut_modifier #self_selector, other_value)?;
809 }
810 }),
811 (FieldHandling::OptionedOnly, _) =>None,
812 }
813 },
814 );
815
816 quote! {
817 #(#fields_token)*
818 }
819}
820fn optioned_ty(crate_name: &Path, ty: &Type) -> TokenStream {
825 if is_self_resolving_optioned(ty) {
826 ty.to_token_stream()
827 } else {
828 quote! { <#ty as #crate_name::Optionable>::Optioned }
829 }
830}
831
832const SELF_RESOLVING_TYPES: [&str; 18] = [
833 "i8", "i16", "i32", "i64", "i128", "isize", "u8", "u16", "u32", "u64", "u128", "usize", "f32",
835 "f64", "char", "bool", "String", "OsString",
837];
838
839fn is_self_resolving_optioned(ty: &Type) -> bool {
842 if let Type::Path(TypePath { qself, path }) = &ty
843 && qself.is_none()
844 && SELF_RESOLVING_TYPES.contains(&&*path.to_token_stream().to_string())
845 {
846 true
847 } else {
848 false
849 }
850}
851
852fn forwarded_attributes(
855 attrs: &[Attribute],
856 attr_to_copy: &HashMap<Path, HashSet<Path>>,
857) -> Result<Option<TokenStream>, Error> {
858 let forward_attrs = attrs
859 .iter()
860 .map(|attr| {
861 if attr.path().is_ident(HELPER_ATTR_IDENT) {
862 return match &attr.meta {
863 Meta::List(MetaList { tokens, .. }) => Ok(Some(quote!(#[#tokens]))),
864 _ => error("Only lists like `#[optionable_attr(Serialize,Deserialize)]` are supported for `optionable_attr`"),
865 };
866 }
867 let keys_to_copy = attr_to_copy.get(attr.path());
868 if let Some(keys_to_copy) = keys_to_copy {
869 if keys_to_copy.is_empty() {
871 if attr.path().is_ident("derive") && let Meta::List(meta_list) = &attr.meta {
872 let derives = Punctuated::<Path, Token![,]>::parse_terminated
873 .parse2(meta_list.tokens.clone())?.into_iter().filter(|el| el.to_token_stream().to_string() != "Optionable" && el.to_token_stream().to_string() != "optionable::Optionable");
874 return Ok(Some(quote! {#[derive(#(#derives,)*)]}));
875 }
876 Ok(Some(attr.to_token_stream()))
877 } else {
878 match &attr.meta {
879 Meta::Path(_) => Ok(None),
880 Meta::NameValue(meta_name_value) => Ok(keys_to_copy.contains(&meta_name_value.path).then(|| attr.to_token_stream())),
881 Meta::List(meta_list) => {
882 let inner_metas: Vec<TokenStream> = Punctuated::<Meta, Token![,]>::parse_terminated
884 .parse2(meta_list.tokens.clone())?.into_iter().filter_map(|meta| {
885 if let Meta::NameValue(meta_name_value) = meta {
886 keys_to_copy.contains(&meta_name_value.path).then(|| Ok::<_, Error>(meta_name_value.to_token_stream()))
887 } else {
888 None
889 }
890 }).collect::<Result<_, _>>()?;
891 if inner_metas.is_empty() {
892 Ok(None)
893 } else {
894 let attr = Attribute {
895 meta: MetaList {
896 path: meta_list.path.clone(),
897 delimiter: meta_list.delimiter.clone(),
898 tokens: inner_metas.into_iter().collect(),
899 }.into(),
900 ..*attr
901 };
902 Ok(Some(attr.to_token_stream()))
903 }
904 }
905 }
906 }
907 } else {
908 Ok(None)
909 }
910 })
911 .collect::<Result<Vec<_>, _>>()?
912 .into_iter()
913 .flatten()
914 .collect::<TokenStream>();
915 Ok((!forward_attrs.is_empty()).then_some(forward_attrs))
916}
917
918#[cfg(test)]
919mod tests {
920 use crate::{derive_optionable, CodegenSettings};
921 use darling::FromMeta;
922 use proc_macro2::TokenStream;
923 use quote::quote;
924 use syn::{parse_quote, Path};
925
926 struct TestCase {
927 input: TokenStream,
928 output: TokenStream,
929 }
930
931 #[test]
932 #[allow(clippy::too_many_lines)]
933 fn test_optionable() {
934 let tcs = vec![
935 TestCase {
937 input: quote! {
938 #[derive(Optionable)]
939 struct DeriveExample {
940 name: String,
941 pub surname: String,
942 }
943 },
944 output: quote! {
945 struct DeriveExampleOpt {
946 name: Option<String>,
947 pub surname: Option<String>
948 }
949
950 #[automatically_derived]
951 impl ::optionable::Optionable for DeriveExample {
952 type Optioned = DeriveExampleOpt;
953 }
954
955 #[automatically_derived]
956 impl ::optionable::Optionable for DeriveExampleOpt {
957 type Optioned = DeriveExampleOpt;
958 }
959
960 #[automatically_derived]
961 impl ::optionable::OptionableConvert for DeriveExample {
962 fn into_optioned (self) -> DeriveExampleOpt {
963 DeriveExampleOpt {
964 name: Some(self.name),
965 surname:Some(self.surname)
966 }
967 }
968
969 fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
970 Ok(Self{
971 name: value.name.ok_or(::optionable::Error { missing_field: "name" })?,
972 surname: value.surname.ok_or(::optionable::Error { missing_field: "surname" })?
973 })
974 }
975
976 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
977 if let Some(other_value) = other.name {
978 self.name = other_value;
979 }
980 if let Some(other_value) = other.surname {
981 self.surname = other_value;
982 }
983 Ok(())
984 }
985 }
986
987 #[automatically_derived]
988 impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
989 fn from_optionable(value: DeriveExample) -> Self {
990 ::optionable::OptionableConvert::into_optioned(value)
991 }
992
993 fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
994 ::optionable::OptionableConvert::try_from_optioned(self)
995 }
996
997 fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
998 ::optionable::OptionableConvert::merge(other, self)
999 }
1000 }
1001 },
1002 },
1003 TestCase {
1005 input: quote! {
1006 #[derive(Optionable)]
1007 #[optionable(no_convert)]
1008 struct DeriveExample {
1009 name: String,
1010 pub surname: String,
1011 }
1012 },
1013 output: quote! {
1014 struct DeriveExampleOpt {
1015 name: Option<String>,
1016 pub surname: Option<String>
1017 }
1018
1019 #[automatically_derived]
1020 impl ::optionable::Optionable for DeriveExample {
1021 type Optioned = DeriveExampleOpt;
1022 }
1023
1024 #[automatically_derived]
1025 impl ::optionable::Optionable for DeriveExampleOpt {
1026 type Optioned = DeriveExampleOpt;
1027 }
1028 },
1029 },
1030 TestCase {
1032 input: quote! {
1033 #[derive(Optionable)]
1034 struct DeriveExample {
1035 name: String,
1036 #[optionable(required)]
1037 pub surname: String,
1038 #[optionable(optioned_type=MyInt)]
1039 pub id: i32,
1040 }
1041 },
1042 output: quote! {
1043 struct DeriveExampleOpt {
1044 name: Option<String>,
1045 pub surname: String,
1046 pub id: Option<MyInt>
1047 }
1048
1049 #[automatically_derived]
1050 impl ::optionable::Optionable for DeriveExample {
1051 type Optioned = DeriveExampleOpt;
1052 }
1053
1054 #[automatically_derived]
1055 impl ::optionable::Optionable for DeriveExampleOpt {
1056 type Optioned = DeriveExampleOpt;
1057 }
1058
1059 #[automatically_derived]
1060 impl ::optionable::OptionableConvert for DeriveExample {
1061 fn into_optioned (self) -> DeriveExampleOpt {
1062 DeriveExampleOpt {
1063 name: Some(self.name),
1064 surname: self.surname,
1065 id: Some (::optionable::OptionedConvert::from_optionable(self.id))
1066 }
1067 }
1068
1069 fn try_from_optioned(value:DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
1070 Ok (Self {
1071 name: value.name.ok_or(::optionable::Error { missing_field: "name" })?,
1072 surname: value.surname,
1073 id: ::optionable::OptionedConvert::try_into_optionable(value.id.ok_or(::optionable::Error{ missing_field: "id" })?)?
1074 })
1075 }
1076
1077 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
1078 if let Some(other_value) = other.name {
1079 self.name = other_value;
1080 }
1081 self.surname = other.surname;
1082 if let Some (other_value) = other.id {
1083 ::optionable::OptionedConvert::merge_into(other_value, &mut self.id)?;
1084 }
1085 Ok (())
1086 }
1087 }
1088
1089
1090 #[automatically_derived]
1091 impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
1092 fn from_optionable(value: DeriveExample) -> Self {
1093 ::optionable::OptionableConvert::into_optioned(value)
1094 }
1095
1096 fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1097 ::optionable::OptionableConvert::try_from_optioned(self)
1098 }
1099
1100 fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1101 ::optionable::OptionableConvert::merge(other, self)
1102 }
1103 }
1104 },
1105 },
1106 TestCase {
1108 input: quote! {
1109 #[derive(Optionable)]
1110 #[optionable(derive(Deserialize,Serialize,Default),suffix="Ac")]
1111 #[optionable(attr_copy(attr=serde,key=rename))]
1112 #[optionable_attr(serde(rename_all_fields = "camelCase", deny_unknown_fields))]
1113 #[optionable_attr(serde(default))]
1114 struct DeriveExample {
1115 #[optionable_attr(serde(rename = "firstName"))]
1116 name: String,
1117 #[serde(rename="middle__name")]
1118 middle_name: Option<String>,
1119 surname: String,
1120 }
1121 },
1122 output: quote! {
1123 #[derive(Default, Deserialize, Serialize)]
1124 #[serde(rename_all_fields = "camelCase", deny_unknown_fields)]
1125 #[serde(default)]
1126 struct DeriveExampleAc {
1127 #[serde(rename = "firstName")]
1128 #[serde(skip_serializing_if = "Option::is_none")]
1129 name: Option<String>,
1130 #[serde(rename = "middle__name")]
1131 #[serde(skip_serializing_if = "Option::is_none")]
1132 middle_name: <Option<String> as ::optionable::Optionable>::Optioned,
1133 #[serde(skip_serializing_if = "Option::is_none")]
1134 surname: Option<String>
1135 }
1136
1137 #[automatically_derived]
1138 impl ::optionable::Optionable for DeriveExample {
1139 type Optioned = DeriveExampleAc;
1140 }
1141
1142 #[automatically_derived]
1143 impl ::optionable::Optionable for DeriveExampleAc {
1144 type Optioned = DeriveExampleAc;
1145 }
1146
1147 #[automatically_derived]
1148 impl ::optionable::OptionableConvert for DeriveExample {
1149 fn into_optioned (self) -> DeriveExampleAc {
1150 DeriveExampleAc {
1151 name: Some(self.name),
1152 middle_name: ::optionable::OptionableConvert::into_optioned(self.middle_name),
1153 surname: Some(self.surname)
1154 }
1155 }
1156
1157 fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::Error> {
1158 Ok(Self{
1159 name: value.name.ok_or(::optionable::Error { missing_field: "name"})?,
1160 middle_name: ::optionable::OptionableConvert::try_from_optioned(value.middle_name)?,
1161 surname: value.surname.ok_or(::optionable::Error { missing_field: "surname"})?
1162 })
1163 }
1164
1165 fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::Error> {
1166 if let Some(other_value) = other.name {
1167 self.name = other_value;
1168 }
1169 ::optionable::OptionableConvert::merge(&mut self.middle_name, other.middle_name)?;
1170 if let Some(other_value) = other.surname {
1171 self.surname = other_value;
1172 }
1173 Ok(())
1174 }
1175 }
1176
1177
1178 #[automatically_derived]
1179 impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleAc {
1180 fn from_optionable(value: DeriveExample) -> Self {
1181 ::optionable::OptionableConvert::into_optioned(value)
1182 }
1183
1184 fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1185 ::optionable::OptionableConvert::try_from_optioned(self)
1186 }
1187
1188 fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1189 ::optionable::OptionableConvert::merge(other, self)
1190 }
1191 }
1192 },
1193 },
1194 TestCase {
1196 input: quote! {
1197 #[derive(Optionable)]
1198 #[optionable(derive(serde::Deserialize,serde::Serialize),suffix="Ac")]
1199 struct DeriveExample {
1200 name: String,
1201 surname: String,
1202 }
1203 },
1204 output: quote! {
1205 #[derive(serde::Deserialize, serde::Serialize)]
1206 struct DeriveExampleAc {
1207 #[serde(skip_serializing_if = "Option::is_none")]
1208 name: Option<String>,
1209 #[serde(skip_serializing_if = "Option::is_none")]
1210 surname: Option<String>
1211 }
1212
1213 #[automatically_derived]
1214 impl ::optionable::Optionable for DeriveExample {
1215 type Optioned = DeriveExampleAc;
1216 }
1217
1218 #[automatically_derived]
1219 impl ::optionable::Optionable for DeriveExampleAc {
1220 type Optioned = DeriveExampleAc;
1221 }
1222
1223 #[automatically_derived]
1224 impl ::optionable::OptionableConvert for DeriveExample {
1225 fn into_optioned (self) -> DeriveExampleAc {
1226 DeriveExampleAc {
1227 name: Some(self.name),
1228 surname: Some(self.surname)
1229 }
1230 }
1231
1232 fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::Error> {
1233 Ok(Self{
1234 name: value.name.ok_or(::optionable::Error{ missing_field: "name"})?,
1235 surname: value.surname.ok_or(::optionable::Error{ missing_field: "surname"})?
1236 })
1237 }
1238
1239 fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::Error> {
1240 if let Some(other_value) = other.name {
1241 self.name = other_value;
1242 }
1243 if let Some(other_value) = other.surname {
1244 self.surname = other_value;
1245 }
1246 Ok(())
1247 }
1248 }
1249
1250 #[automatically_derived]
1251 impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleAc {
1252 fn from_optionable(value: DeriveExample) -> Self {
1253 ::optionable::OptionableConvert::into_optioned(value)
1254 }
1255
1256 fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1257 ::optionable::OptionableConvert::try_from_optioned(self)
1258 }
1259
1260 fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1261 ::optionable::OptionableConvert::merge(other, self)
1262 }
1263 }
1264 },
1265 },
1266 TestCase {
1268 input: quote! {
1269 #[derive(Optionable)]
1270 struct DeriveExample(pub String, i32);
1271 },
1272 output: quote! {
1273 struct DeriveExampleOpt(
1274 pub Option<String>,
1275 Option<i32>
1276 );
1277
1278 #[automatically_derived]
1279 impl ::optionable::Optionable for DeriveExample {
1280 type Optioned = DeriveExampleOpt;
1281 }
1282
1283 #[automatically_derived]
1284 impl ::optionable::Optionable for DeriveExampleOpt {
1285 type Optioned = DeriveExampleOpt;
1286 }
1287
1288 #[automatically_derived]
1289 impl ::optionable::OptionableConvert for DeriveExample {
1290 fn into_optioned (self) -> DeriveExampleOpt {
1291 DeriveExampleOpt (
1292 Some(self.0),
1293 Some(self.1)
1294 )
1295 }
1296
1297 fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
1298 Ok(Self(
1299 value.0.ok_or(::optionable::Error { missing_field:"0" })?,
1300 value.1.ok_or(::optionable::Error { missing_field: "1" })?
1301 ))
1302 }
1303
1304 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
1305 if let Some(other_value) = other.0 {
1306 self.0 = other_value;
1307 }
1308 if let Some (other_value) = other.1 {
1309 self.1 = other_value;
1310 }
1311 Ok (())
1312 }
1313 }
1314
1315
1316 #[automatically_derived]
1317 impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
1318 fn from_optionable(value: DeriveExample) -> Self {
1319 ::optionable::OptionableConvert::into_optioned(value)
1320 }
1321
1322 fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1323 ::optionable::OptionableConvert::try_from_optioned(self)
1324 }
1325
1326 fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1327 ::optionable::OptionableConvert::merge(other, self)
1328 }
1329 }
1330 },
1331 },
1332 TestCase {
1334 input: quote! {
1335 #[derive(Optionable)]
1336 struct DeriveExample(pub String, #[optionable(required)] i32);
1337 },
1338 output: quote! {
1339 struct DeriveExampleOpt(
1340 pub Option<String>,
1341 i32
1342 );
1343
1344 #[automatically_derived]
1345 impl ::optionable::Optionable for DeriveExample {
1346 type Optioned = DeriveExampleOpt;
1347 }
1348
1349 #[automatically_derived]
1350 impl ::optionable::Optionable for DeriveExampleOpt {
1351 type Optioned = DeriveExampleOpt;
1352 }
1353
1354 # [automatically_derived]
1355 impl ::optionable::OptionableConvert for DeriveExample {
1356 fn into_optioned (self) -> DeriveExampleOpt {
1357 DeriveExampleOpt (
1358 Some(self.0),
1359 self.1
1360 )
1361 }
1362
1363 fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
1364 Ok(Self(
1365 value.0.ok_or(::optionable::Error { missing_field: "0" })?,
1366 value.1))
1367 }
1368
1369 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
1370 if let Some(other_value) = other.0 {
1371 self.0 = other_value;
1372 }
1373 self.1 = other.1;
1374 Ok (())
1375 }
1376 }
1377
1378
1379 #[automatically_derived]
1380 impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
1381 fn from_optionable(value: DeriveExample) -> Self {
1382 ::optionable::OptionableConvert::into_optioned(value)
1383 }
1384
1385 fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1386 ::optionable::OptionableConvert::try_from_optioned(self)
1387 }
1388
1389 fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1390 ::optionable::OptionableConvert::merge(other, self)
1391 }
1392 }
1393 },
1394 },
1395 TestCase {
1397 input: quote! {
1398 #[derive(Optionable)]
1399 #[optionable(derive(Serialize, Deserialize))]
1400 struct DeriveExample<'a, T, T2: Serialize, T3> {
1401 output: T,
1402 input: Cow<'a, T2>,
1403 #[optionable(required)]
1404 extra: T3,
1405 }
1406 },
1407 output: quote! {
1408 #[derive (Deserialize, Serialize)]
1409 struct DeriveExampleOpt<'a, T, T2: Serialize, T3>
1410 where T: ::optionable::Optionable,
1411 <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1412 Cow<'a ,T2>: ::optionable::Optionable,
1413 <Cow<'a,T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1414 {
1415 #[serde(skip_serializing_if="Option::is_none")]
1416 output: Option< <T as ::optionable::Optionable>::Optioned>,
1417 #[serde(skip_serializing_if="Option::is_none")]
1418 input: Option< <Cow<'a, T2> as ::optionable::Optionable>::Optioned>,
1419 extra: T3
1420 }
1421
1422 #[automatically_derived]
1423 impl<'a, T, T2: Serialize, T3> ::optionable::Optionable for DeriveExample<'a, T, T2, T3>
1424 where T: ::optionable::Optionable,
1425 <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1426 Cow<'a, T2>: ::optionable::Optionable,
1427 <Cow<'a, T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1428 {
1429 type Optioned = DeriveExampleOpt<'a, T,T2,T3>;
1430 }
1431
1432 #[automatically_derived]
1433 impl<'a, T, T2: Serialize, T3> ::optionable::Optionable for DeriveExampleOpt<'a ,T, T2, T3>
1434 where T: ::optionable::Optionable,
1435 <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1436 Cow<'a, T2>: ::optionable::Optionable,
1437 <Cow<'a, T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1438 {
1439 type Optioned = DeriveExampleOpt<'a, T, T2, T3>;
1440 }
1441
1442 #[automatically_derived]
1443 impl <'a, T, T2:Serialize, T3> ::optionable::OptionableConvert for DeriveExample<'a, T, T2, T3>
1444 where T: ::optionable::OptionableConvert,
1445 <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1446 Cow<'a, T2>: ::optionable::OptionableConvert,
1447 <Cow<'a, T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1448 {
1449 fn into_optioned (self) -> DeriveExampleOpt<'a, T, T2, T3> {
1450 DeriveExampleOpt::<'a, T, T2, T3> {
1451 output: Some(::optionable::OptionableConvert::into_optioned(self.output)),
1452 input: Some(::optionable::OptionableConvert::into_optioned(self.input)),
1453 extra: self.extra
1454 }
1455 }
1456
1457 fn try_from_optioned(value: DeriveExampleOpt<'a, T, T2, T3> ) -> Result <Self, ::optionable::Error> {
1458 Ok(Self{
1459 output: ::optionable::OptionableConvert::try_from_optioned(value.output.ok_or(::optionable::Error { missing_field: "output" })?)?,
1460 input: ::optionable::OptionableConvert::try_from_optioned(value.input.ok_or(::optionable::Error { missing_field: "input" })?)?,
1461 extra: value.extra
1462 })
1463 }
1464
1465 fn merge(&mut self, other: DeriveExampleOpt<'a, T, T2, T3> ) -> Result<(), ::optionable::Error> {
1466 if let Some(other_value) = other.output {
1467 ::optionable::OptionableConvert::merge(&mut self.output, other_value)?;
1468 }
1469 if let Some(other_value) = other.input {
1470 ::optionable::OptionableConvert::merge(&mut self.input, other_value)?;
1471 }
1472 self.extra=other.extra;
1473 Ok(())
1474 }
1475 }
1476
1477
1478 #[automatically_derived]
1479 impl <'a, T, T2:Serialize, T3> ::optionable::OptionedConvert<DeriveExample<'a, T, T2, T3> > for DeriveExampleOpt<'a, T, T2, T3>
1480 where T: ::optionable::OptionableConvert,
1481 <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1482 Cow<'a, T2>: ::optionable::OptionableConvert,
1483 <Cow<'a, T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1484 {
1485 fn from_optionable(value: DeriveExample<'a, T, T2, T3>) -> Self {
1486 ::optionable::OptionableConvert::into_optioned(value)
1487 }
1488
1489 fn try_into_optionable(self) -> Result<DeriveExample<'a, T, T2, T3>, ::optionable::Error> {
1490 ::optionable::OptionableConvert::try_from_optioned(self)
1491 }
1492
1493 fn merge_into(self, other: &mut DeriveExample<'a, T, T2, T3>) -> Result<(), ::optionable::Error> {
1494 ::optionable::OptionableConvert::merge(other, self)
1495 }
1496 }
1497 },
1498 },
1499 TestCase {
1500 input: quote! {
1501 #[derive(Optionable)]
1502 enum DeriveExample {
1503 Unit,
1504 Plain(String),
1505 Address{street: String, number: u32},
1506 Address2(String,u32),
1507 }
1508 },
1509 output: quote! {
1510 enum DeriveExampleOpt {
1511 Unit,
1512 Plain( Option<String> ),
1513 Address{ street: Option<String>, number:Option<u32> },
1514 Address2( Option<String>, Option<u32> )
1515 }
1516
1517 #[automatically_derived]
1518 impl ::optionable::Optionable for DeriveExample {
1519 type Optioned = DeriveExampleOpt;
1520 }
1521
1522 #[automatically_derived]
1523 impl ::optionable::Optionable for DeriveExampleOpt {
1524 type Optioned = DeriveExampleOpt;
1525 }
1526
1527 #[automatically_derived]
1528 impl ::optionable::OptionableConvert for DeriveExample {
1529 fn into_optioned (self) -> DeriveExampleOpt {
1530 match self{
1531 Self::Unit => DeriveExampleOpt::Unit,
1532 Self::Plain(self_0) => DeriveExampleOpt::Plain(
1533 Some(self_0)
1534 ),
1535 Self::Address{street: self_street, number: self_number} => DeriveExampleOpt::Address{
1536 street: Some(self_street),
1537 number: Some(self_number)
1538 },
1539 Self::Address2(self_0, self_1) => DeriveExampleOpt::Address2(
1540 Some(self_0),
1541 Some(self_1)
1542 )
1543 }
1544 }
1545
1546 fn try_from_optioned(other: DeriveExampleOpt) -> Result <Self, ::optionable::Error> {
1547 Ok (match other {
1548 DeriveExampleOpt::Unit => Self::Unit,
1549 DeriveExampleOpt::Plain(other_0) => Self::Plain(
1550 other_0.ok_or(::optionable::Error { missing_field: "0" })?
1551 ),
1552 DeriveExampleOpt::Address{street: other_street, number: other_number} => Self::Address{
1553 street: other_street.ok_or(::optionable::Error { missing_field: "street" })?,
1554 number: other_number.ok_or(::optionable::Error { missing_field: "number" })?
1555 },
1556 DeriveExampleOpt::Address2(other_0, other_1) => Self::Address2(
1557 other_0.ok_or(::optionable::Error { missing_field: "0"})?,
1558 other_1.ok_or(::optionable::Error { missing_field: "1"})?)
1559 })
1560 }
1561
1562 fn merge(&mut self, other: DeriveExampleOpt) -> Result<(), ::optionable::Error> {
1563 match other {
1564 DeriveExampleOpt::Unit => {
1565 if let Self::Unit = self {} else {
1566 *self = Self::try_from_optioned(DeriveExampleOpt::Unit)?;
1567 }
1568 },
1569 DeriveExampleOpt::Plain(other_0) => {
1570 if let Self::Plain(self_0) = self{
1571 if let Some(other_value) = other_0 {
1572 *self_0 = other_value;
1573 }
1574 } else {
1575 *self = Self::try_from_optioned(DeriveExampleOpt::Plain(other_0))?;
1576 }
1577 },
1578 DeriveExampleOpt::Address{street: other_street, number: other_number} => {
1579 if let Self::Address{street: self_street, number: self_number} = self{
1580 if let Some(other_value) = other_street {
1581 *self_street = other_value;
1582 }
1583 if let Some(other_value) = other_number {
1584 *self_number = other_value;
1585 }
1586 } else {
1587 *self = Self::try_from_optioned(DeriveExampleOpt::Address{street: other_street, number: other_number})?;
1588 }
1589 },
1590 DeriveExampleOpt::Address2(other_0, other_1) => {
1591 if let Self::Address2(self_0, self_1) = self{
1592 if let Some(other_value) = other_0 {
1593 *self_0 = other_value;
1594 }
1595 if let Some(other_value) = other_1 {
1596 *self_1 = other_value;
1597 }
1598 } else {
1599 *self = Self::try_from_optioned(DeriveExampleOpt::Address2(other_0, other_1))?;
1600 }
1601 }
1602 }
1603 Ok(())
1604 }
1605 }
1606
1607 #[automatically_derived]
1608 impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
1609 fn from_optionable(value: DeriveExample) -> Self {
1610 ::optionable::OptionableConvert::into_optioned(value)
1611 }
1612
1613 fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1614 ::optionable::OptionableConvert::try_from_optioned(self)
1615 }
1616
1617 fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1618 ::optionable::OptionableConvert::merge(other, self)
1619 }
1620 }
1621 },
1622 },
1623 TestCase {
1624 input: quote! {
1625 #[derive(Optionable)]
1626 enum DeriveExample {
1627 Unit,
1628 Unit2,
1629 Unit3
1630 }
1631 },
1632 output: quote! {
1633 #[automatically_derived]
1634 impl ::optionable::Optionable for DeriveExample {
1635 type Optioned = Self;
1636 }
1637
1638 #[automatically_derived]
1639 impl ::optionable::OptionableConvert for DeriveExample {
1640 fn into_optioned(self) -> DeriveExample{
1641 self
1642 }
1643
1644 fn try_from_optioned(value: Self::Optioned) -> Result <Self , ::optionable::Error> {
1645 Ok (value)
1646 }
1647
1648 fn merge (&mut self , other: Self::Optioned) -> Result <() , ::optionable::Error> {
1649 *self = other;
1650 Ok(())
1651 }
1652 }
1653 },
1654 },
1655 ];
1656 for tc in tcs {
1657 let input = syn::parse2(tc.input).unwrap();
1658 let output = derive_optionable(input, None).unwrap();
1659 println!("{output}");
1660 assert_eq!(tc.output.to_string(), output.to_string());
1661 }
1662 }
1663
1664 #[test]
1665 #[allow(clippy::too_many_lines)]
1666 fn test_crate_replacement() {
1668 let tcs = vec![TestCase {
1669 input: quote! {
1670 #[derive(Optionable)]
1671 struct DeriveExample {
1672 name: crate::Name,
1673 pub surname: Box<crate::SurName>,
1674 }
1675 },
1676 output: quote! {
1677 struct DeriveExampleOpt {
1678 name: Option< <::testcrate::Name as crate::Optionable>::Optioned>,
1679 pub surname: Option< <Box<::testcrate::SurName> as crate::Optionable>::Optioned>
1680 }
1681
1682 #[automatically_derived]
1683 impl crate::Optionable for crate_prefix::DeriveExample {
1684 type Optioned = DeriveExampleOpt;
1685 }
1686
1687 #[automatically_derived]
1688 impl crate::Optionable for DeriveExampleOpt {
1689 type Optioned = DeriveExampleOpt;
1690 }
1691
1692 #[automatically_derived]
1693 impl crate::OptionableConvert for crate_prefix::DeriveExample {
1694 fn into_optioned (self) -> DeriveExampleOpt {
1695 DeriveExampleOpt {
1696 name: Some(crate::OptionableConvert::into_optioned(self.name)),
1697 surname: Some(crate::OptionableConvert::into_optioned(self.surname))
1698 }
1699 }
1700
1701 fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, crate::Error> {
1702 Ok(Self{
1703 name: crate::OptionableConvert::try_from_optioned(value.name.ok_or(crate::Error { missing_field: "name" })?)?,
1704 surname: crate::OptionableConvert::try_from_optioned(value.surname.ok_or(crate::Error { missing_field: "surname" })?)?
1705 })
1706 }
1707
1708 fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), crate::Error> {
1709 if let Some(other_value) = other.name {
1710 crate::OptionableConvert::merge(&mut self.name, other_value)?;
1711 }
1712 if let Some(other_value) = other.surname {
1713 crate::OptionableConvert::merge(&mut self.surname, other_value)?;
1714 }
1715 Ok(())
1716 }
1717 }
1718
1719 #[automatically_derived]
1720 impl crate::OptionedConvert<crate_prefix::DeriveExample> for DeriveExampleOpt {
1721 fn from_optionable(value: crate_prefix::DeriveExample) -> Self {
1722 crate::OptionableConvert::into_optioned(value)
1723 }
1724
1725 fn try_into_optionable(self) -> Result<crate_prefix::DeriveExample, crate::Error> {
1726 crate::OptionableConvert::try_from_optioned(self)
1727 }
1728
1729 fn merge_into(self, other: &mut crate_prefix::DeriveExample) -> Result<(), crate::Error> {
1730 crate::OptionableConvert::merge(other, self)
1731 }
1732 }
1733 },
1734 }];
1735 for tc in tcs {
1736 let input = syn::parse2(tc.input).unwrap();
1737 let output = derive_optionable(
1738 input,
1739 Some(&CodegenSettings {
1740 ty_prefix: Some(Path::from_string("crate_prefix").unwrap()),
1741 optionable_crate_name: Path::from_string("crate").unwrap(),
1742 input_crate_replacement: Some(parse_quote!(testcrate)),
1743 }),
1744 )
1745 .unwrap();
1746 assert_eq!(tc.output.to_string(), output.to_string());
1747 }
1748 }
1749}