optionable_codegen/
lib.rs

1//! The relevant main crate is [optionable](https://crates.io/crates/optionable). The docs can be found there.
2//!
3//! # Purpose
4//! This code generation `proc_macro2` library serves two purposes:
5//! - Used by [optionable_derive](https://crates.io/crates/optionable_derive) to implement the `#[derive(Optionable)]`-macro
6//!   re-exported by [optionable](https://crates.io/crates/optionable_derive).
7//! - Used by the [bin/codegen.rs](bin/codegen.rs) crate to support generating `Optionable`-implementations for external packages.
8//!   Due to the orphan rule  the generated code has to be added to the `Optionable`-package (PRs welcome).
9//!
10//! It has to be a separate crate from [optionable_derive](https://crates.io/crates/optionable_derive) as the proc-macro crates
11//! can't export its non-macro functions (even the `proc_macro2` ones) for the usage by the codegen part.
12
13mod 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 syn::parse::Parser;
36use syn::punctuated::Punctuated;
37use syn::spanned::Spanned;
38use syn::{
39    parse_quote, Attribute, Data, DeriveInput, Error, Field, LitStr, Meta, MetaList, Path, Token,
40    Type, TypePath, WhereClause,
41};
42
43const HELPER_IDENT: &str = "optionable";
44const HELPER_ATTR_IDENT: &str = "optionable_attr";
45const ERR_MSG_HELPER_ATTR_ENUM_VARIANTS: &str =
46    "#[optionable] helper attributes not supported on enum variant level.";
47
48#[derive(FromDeriveInput)]
49#[darling(attributes(optionable))]
50/// Helper attributes on the type definition level (attached to the `struct` or `enum` itself).
51pub(crate) struct TypeHelperAttributes {
52    /// Forwards the specified `attr` to the definition of the optioned type.
53    /// If any `key` is set it filters the configuration of the forwarded attributes for the specified configuration names.
54    /// E.g. `#[optionable(attr_copy(attr=serde,key=rename)]` will only forward the `rename`sub-attribute of serde.
55    #[darling(multiple)]
56    attr_copy: Vec<FieldAttributeToCopy>,
57    /// Derive-macros that should be added to the optioned type
58    #[darling(multiple)]
59    derive: Vec<PathList>,
60    /// Explicit suffix to use for the optioned type.
61    suffix: Option<LitStr>,
62    /// Skip generating `OptionableConvert` impl
63    no_convert: Option<()>,
64    /// Adjustments of the derived optioned type for fields that use the `k8s_openapi` serialization replacements.
65    /// - Derives for the optioned type `Clone, Debug, PartialEq, Serialize, Deserialize` and additionally for Structs `Default`.
66    /// - Takes the `k8s_openapi` serialization replacements into account for its own serialization.
67    k8s_openapi: Option<TypeHelperAttributesK8sOpenapi>,
68    /// Adjustments of the derived optioned type for structs that `kube::CustomResource` or respective subfields.
69    /// - Derives for the optioned type `Clone, Debug, PartialEq, Serialize, Deserialize` and additionally for Structs `Default`.
70    /// - Copy `#[(serde(rename="...")]` and `#[(serde(rename_all="...")]` attributes over to the optioned types.
71    kube: Option<TypeHelperAttributesKube>,
72}
73
74#[derive(FromMeta)]
75/// Adjustments of the derived optioned type for fields that use the `k8s_openapi` serialization replacements.
76/// - Derives for the optioned type `Clone, Debug, PartialEq, Serialize, Deserialize` and additionally for Structs `Default`.
77/// - Takes the `k8s_openapi` serialization replacements into account for its own serialization.
78pub(crate) struct TypeHelperAttributesK8sOpenapi {
79    /// Adjustments of the derived optioned type for `k8s_openapi::Metadata`-implementations.
80    /// - Sets the `metadata` field as required for the optioned type.
81    /// - Derives `k8s_openapi::Metadata` for the optioned type.
82    metadata: Option<()>,
83    /// Adjustments of the derived optioned type for `k8s_openapi::Resource`-implementations.
84    /// - Adds `apiVersion` and `kind` to the serialization output with values from the trait constants of the given `k8s_openapi::Resource` implementation
85    /// - Derives `k8s_openapi::resource` for the optioned type.
86    resource: Option<()>,
87}
88
89#[derive(FromMeta)]
90/// Adjustments of the derived optioned type for structs that `kube::CustomResource` or respective subfields.
91/// - Derives for the optioned type `Clone, Debug, PartialEq, Serialize, Deserialize` and additionally for Structs `Default`.
92pub(crate) struct TypeHelperAttributesKube {
93    /// Adjustments of the derived optioned type for `kube::Resource`-implementations.
94    /// - Sets the `metadata` field as required for the optioned type.
95    /// - Adds `apiVersion` and `kind` to the serialization output with values from the trait constants of the given `kube::Resource` implementation
96    /// - Derives `kube::Resource` for the optioned type.
97    resource: Option<()>,
98}
99
100#[derive(FromMeta)]
101/// Forwards the specified `attr` to the definition of the optioned type.
102/// If `sub_names` is set it filters the configuration of the forwarded attribure for the specified configuration names.
103/// E.g. `attr=serde,sub_names=rename` will only forward the `rename`sub-attribute of serde.
104pub struct FieldAttributeToCopy {
105    pub attr: Path,
106    pub key: Option<Path>,
107}
108
109#[derive(FromDeriveInput, Debug, Clone)]
110#[darling(attributes(optionable))]
111/// Settings that are only available to be set via the rust function signature of `derive_optionable`
112/// but not via the derive macro (as they are not useful in that context and would lead to an
113/// increased but not useful API surface of the derive macro helpers).
114pub struct CodegenSettings {
115    /// Name of the optionable crate to use for the generated code including potentially
116    /// leading `::`. Useful to set when generating code for the `optionable`
117    /// crate itself where one needs to refer to it as `crate`.
118    pub optionable_crate_name: Path,
119    /// Path prefix to prepend to the respective type. E.g. with a `ty_prefix` of `::mycrate`
120    /// the output would be (simplified) `impl Optionable for ::mycrate::mytype`.
121    pub ty_prefix: Option<Path>,
122    /// Replacement for the keyword `crate` in the input type/enum definition or references.
123    /// Useful when generating code for the `optionable` crate as pre-existing `crate` references
124    /// need to be replaced with the concret crate name.
125    pub input_crate_replacement: Option<Ident>,
126}
127
128/// Processes the input field attribute forwards to a `HashMap`.
129/// Adds `attr=serde,key=rename` if the `kube` input attribute is present.
130fn field_attr_copy_hashmap(
131    input: Vec<FieldAttributeToCopy>,
132    attr_kube: Option<&TypeHelperAttributesKube>,
133) -> HashMap<Path, HashSet<Path>> {
134    let mut result = HashMap::<Path, HashSet<Path>>::new();
135    for el in input {
136        if let Some(key) = el.key {
137            if let Some(entry) = result.get_mut(&el.attr) {
138                entry.insert(key);
139            } else {
140                result.insert(el.attr, HashSet::from([key]));
141            }
142        }
143    }
144    if attr_kube.is_some() {
145        let path_serde = Path::from_string("serde").unwrap();
146        let path_rename = Path::from_string("rename").unwrap();
147        let path_rename_all = Path::from_string("rename_all").unwrap();
148        if let Some(entry) = result.get_mut(&path_serde) {
149            // If the keys are empty everything will be copied, so don't restrict it here
150            if !entry.is_empty() {
151                entry.insert(path_rename);
152                entry.insert(path_rename_all);
153            }
154        } else {
155            result.insert(path_serde, HashSet::from([path_rename, path_rename_all]));
156        }
157    }
158    result
159}
160
161impl Default for CodegenSettings {
162    fn default() -> Self {
163        Self {
164            optionable_crate_name: parse_quote!(::optionable),
165            ty_prefix: None,
166            input_crate_replacement: None,
167        }
168    }
169}
170
171#[derive(FromAttributes)]
172#[darling(attributes(optionable))]
173/// Helper attributes on the type definition level (attached to the `struct` or `enum` itself).
174struct FieldHelperAttributes {
175    /// Given field won't be optioned, it will also be required for the derived optioned type.
176    required: Option<()>,
177}
178
179/// Returns the attribute for opting-out of `OptionableConvert`-impl generation.
180#[must_use]
181pub fn attribute_no_convert() -> Attribute {
182    parse_quote!(#[optionable(no_convert)])
183}
184
185/// Returns the attribute for setting a custom struct/enum name suffix instead of `Opt`.
186#[must_use]
187pub fn attribute_suffix(suffix: &str) -> Attribute {
188    parse_quote!(#[optionable(suffix=#suffix)])
189}
190
191/// Returns the attribute for setting that the given identifiers should be added as
192/// derive macro to the optioned struct/enum.
193#[must_use]
194pub fn attribute_derives(derives: &PathList) -> Attribute {
195    parse_quote!(#[optionable(derive(#(#derives),*))])
196}
197
198/// Derives the `Optionable`-trait from the main `optionable`-library.
199///
200/// # Errors
201/// - on misplaced helper attributes
202/// - internal implementation errors
203#[allow(clippy::too_many_lines)]
204#[allow(clippy::items_after_statements)]
205pub fn derive_optionable(
206    input: DeriveInput,
207    settings: Option<&CodegenSettings>,
208) -> syn::Result<TokenStream> {
209    let attrs = TypeHelperAttributes::from_derive_input(&input)?;
210    error_missing_features(&attrs)?;
211    let k8s_resource_type = k8s_resource_type(&attrs)?;
212    let k8s_openapi_attrs = attrs.k8s_openapi.is_some().then(|| k8s_type_attr(&input));
213    let attr_copy_identifier = field_attr_copy_hashmap(attrs.attr_copy, attrs.kube.as_ref());
214
215    let mut derive = attrs
216        .derive
217        .into_iter()
218        .flat_map(|el| {
219            el.iter()
220                .map(|el| el.to_token_stream().to_string())
221                .collect::<Vec<_>>()
222        })
223        .collect::<BTreeSet<_>>();
224    if (attrs.k8s_openapi.is_some() || attrs.kube.is_some())
225        && let Some(k8s_derives) = k8s_derives(&input)
226    {
227        for el in k8s_derives {
228            derive.insert(el);
229        }
230    }
231    let settings = settings.map(Cow::Borrowed).unwrap_or_default();
232    let crate_name = &settings.optionable_crate_name;
233    let ty_attr_forwarded = forwarded_attributes(&input.attrs, &attr_copy_identifier)?;
234    let vis = input.vis;
235    let ty_ident_opt = {
236        let suffix = attrs.suffix.map_or_else(
237            || {
238                if attrs.kube.is_some() || attrs.k8s_openapi.is_some() {
239                    Cow::Borrowed("Ac")
240                } else {
241                    Cow::Borrowed("Opt")
242                }
243            },
244            |s| Cow::Owned(s.value()),
245        );
246        Ident::new(&(input.ident.to_string() + &suffix), input.ident.span())
247    };
248    let ty_ident = if let Some(mut ty_prefix) = settings.ty_prefix.clone() {
249        ty_prefix.segments.push(input.ident.into());
250        ty_prefix
251    } else {
252        input.ident.into()
253    };
254    let (impl_generics, ty_generics, _) = input.generics.split_for_impl();
255    let generics_colon = (!input.generics.params.is_empty()).then(|| quote! {::});
256
257    let skip_optionable_if_serde_serialize =
258        (attrs.k8s_openapi.is_some() // also sets #[derive(Serialize)]
259        || derive.iter().any(|el|is_serialize(el.as_str())))
260        .then(|| quote!(#[serde(skip_serializing_if = "Option::is_none")]));
261
262    /// Helper to collect the enum/struct specific derived code aspects in a typesafe way
263    struct Derived {
264        /// Either `enum` or `struct`
265        enum_struct: TokenStream,
266        /// The generated fields, including wrapping brackets
267        fields: TokenStream,
268        /// The `where`-clause for the `struct_enum` definition
269        where_clause_struct_enum: WhereClause,
270        /// The `where`-clause for the `Optionable`-impl
271        where_clause_impl_optionable: WhereClause,
272        /// The `OptionableConvert` implementation if not configured to be skipped, including the `impl`-wrapper
273        impl_optionable_convert: Option<TokenStream>,
274    }
275    let Derived {
276        enum_struct,
277        fields,
278        where_clause_struct_enum,
279        where_clause_impl_optionable,
280        impl_optionable_convert,
281    } = match input.data {
282        Data::Struct(s) => {
283            let mut struct_parsed = into_field_handling(
284                crate_name.to_owned(),
285                s.fields,
286                settings.input_crate_replacement.as_ref(),
287            )?;
288            k8s_adjust_fields(
289                &mut struct_parsed,
290                attrs.k8s_openapi.as_ref(),
291                attrs.kube.as_ref(),
292                k8s_resource_type.as_ref(),
293                crate_name,
294                &ty_ident_opt,
295                &ty_generics,
296            )?;
297            let WhereClauses {
298                struct_enum_def: where_clause_struct_enum,
299                impl_optionable: where_clause_impl_optionable,
300                impl_optionable_convert: where_clause_impl_optionable_convert,
301            } = where_clauses(
302                crate_name,
303                settings.input_crate_replacement.as_ref(),
304                &input.generics,
305                &derive,
306                attrs.no_convert.is_some(),
307                &struct_parsed.fields,
308            )?;
309            let unnamed_struct_semicolon =
310                (struct_parsed.struct_type == StructType::Unnamed).then(|| quote!(;));
311            let optioned_fields = optioned_fields(
312                &struct_parsed,
313                skip_optionable_if_serde_serialize.as_ref(),
314                &attr_copy_identifier,
315            )?;
316
317            let impl_optionable_convert = attrs.no_convert.is_none().then(|| {
318                let into_optioned_fields = into_optioned(&struct_parsed, |selector| quote! { self.#selector });
319                let try_from_optioned_fields =
320                    try_from_optioned(&struct_parsed, |selector| quote! { value.#selector });
321                let merge_fields = merge_fields(
322                    &struct_parsed,
323                    |selector| quote! { self.#selector },
324                    |selector| quote! { other.#selector },
325                    true);
326                quote! {
327                    #[automatically_derived]
328                    impl #impl_generics #crate_name::OptionableConvert for #ty_ident #ty_generics #where_clause_impl_optionable_convert{
329                        fn into_optioned(self) -> #ty_ident_opt #ty_generics {
330                            #ty_ident_opt #generics_colon #ty_generics #into_optioned_fields
331                        }
332
333                        fn try_from_optioned(value: #ty_ident_opt #ty_generics) -> Result<Self, #crate_name::Error>{
334                            Ok(Self #try_from_optioned_fields)
335                        }
336
337                        fn merge(&mut self, other: #ty_ident_opt #ty_generics) -> Result<(), #crate_name::Error>{
338                            #merge_fields
339                            Ok(())
340                        }
341                    }
342                }
343            });
344            Derived {
345                enum_struct: quote! {struct},
346                fields: quote! {#optioned_fields #unnamed_struct_semicolon},
347                where_clause_struct_enum,
348                where_clause_impl_optionable,
349                impl_optionable_convert,
350            }
351        }
352        Data::Enum(e) => {
353            let self_prefix = quote! {self_};
354            let other_prefix = quote! {other_};
355
356            let variants = e
357                .variants
358                .into_iter()
359                .map(|v| {
360                    error_on_helper_attributes(&v.attrs, ERR_MSG_HELPER_ATTR_ENUM_VARIANTS)?;
361                    let mut field_handling = into_field_handling(
362                        crate_name.to_owned(),
363                        v.fields,
364                        settings.input_crate_replacement.as_ref(),
365                    )?;
366                    k8s_adjust_fields(
367                        &mut field_handling,
368                        attrs.k8s_openapi.as_ref(),
369                        attrs.kube.as_ref(),
370                        k8s_resource_type.as_ref(),
371                        crate_name,
372                        &ty_ident_opt,
373                        &ty_generics,
374                    )?;
375                    Ok::<_, Error>((
376                        v.ident,
377                        forwarded_attributes(&v.attrs, &attr_copy_identifier)?,
378                        field_handling,
379                    ))
380                })
381                .collect::<Result<Vec<_>, _>>()?;
382            let all_fields = variants
383                .iter()
384                .flat_map(|(_, _, fields)| &fields.fields)
385                .collect::<Vec<_>>();
386            let WhereClauses {
387                struct_enum_def: where_clause_struct_enum,
388                impl_optionable: where_clause_impl_optionable,
389                impl_optionable_convert: where_clause_impl_optionable_convert,
390            } = where_clauses(
391                crate_name,
392                settings.input_crate_replacement.as_ref(),
393                &input.generics,
394                &derive,
395                attrs.no_convert.is_some(),
396                all_fields,
397            )?;
398
399            let optioned_variants = variants
400                .iter()
401                .map(|(variant, forward_attrs, f)| {
402                    let fields = optioned_fields(
403                        f,
404                        skip_optionable_if_serde_serialize.as_ref(),
405                        &attr_copy_identifier,
406                    )?;
407                    Ok::<_, Error>(quote!( #forward_attrs #variant #fields ))
408                })
409                .collect::<Result<Vec<_>, _>>()?;
410
411            let impl_optionable_convert = attrs.no_convert.is_none().then(|| {
412                let (into_variants, try_from_variants, merge_variants): (Vec<_>, Vec<_>, Vec<_>) = variants
413                    .iter()
414                    .map(|(variant, _, struct_parsed)| {
415                        let fields_into = into_optioned(struct_parsed, |selector| {
416                            format_ident!("{self_prefix}{selector}").to_token_stream()
417                        });
418                        let fields_try_from = try_from_optioned
419                            (struct_parsed, |selector| {
420                                format_ident!("{other_prefix}{selector}").to_token_stream()
421                            });
422                        let fields_merge = merge_fields(struct_parsed,
423                                                        |selector| format_ident!("{self_prefix}{selector}").to_token_stream(),
424                                                        |selector| format_ident!("{other_prefix}{selector}").to_token_stream(),
425                                                        false);
426                        let self_destructure = destructure(struct_parsed, &self_prefix)?;
427                        let other_destructure = destructure(struct_parsed, &other_prefix)?;
428                        Ok::<_, Error>((
429                            quote!( Self::#variant #self_destructure => #ty_ident_opt::#variant #fields_into ),
430                            quote!( #ty_ident_opt::#variant #other_destructure => Self::#variant #fields_try_from ),
431                            quote!( #ty_ident_opt::#variant #other_destructure => {
432                                if let Self::#variant #self_destructure = self {
433                                    #fields_merge
434                                } else {
435                                    *self = Self::try_from_optioned(#ty_ident_opt::#variant #other_destructure)?;
436                                }
437                            })
438                        ))
439                    })
440                    .collect::<Result<Vec<_>, _>>()?
441                    .into_iter().multiunzip();
442                Ok::<_, Error>(quote! {
443                    #[automatically_derived]
444                    impl #impl_generics #crate_name::OptionableConvert for #ty_ident #ty_generics # where_clause_impl_optionable_convert {
445                        fn into_optioned(self) -> #ty_ident_opt #ty_generics {
446                            match self {
447                                #(#into_variants),*
448                            }
449                        }
450
451                        fn try_from_optioned(other: #ty_ident_opt #ty_generics)->Result<Self,#crate_name::Error>{
452                            Ok(match other{
453                                #(#try_from_variants),*
454                            })
455                        }
456
457                        fn merge(&mut self, other: #ty_ident_opt #ty_generics) -> Result<(), #crate_name::Error>{
458                            match other{
459                                #(#merge_variants),*
460                            }
461                            Ok(())
462                        }
463                    }
464                })
465            }).transpose()?;
466            Derived {
467                enum_struct: quote! {enum},
468                fields: quote! {{#(#optioned_variants),*}},
469                where_clause_struct_enum,
470                where_clause_impl_optionable,
471                impl_optionable_convert,
472            }
473        }
474        Data::Union(_) => return error("#[derive(Optionable)] not supported for unit structs"),
475    };
476
477    let derive = derive
478        .into_iter()
479        .map(|derive| Path::from_string(&derive))
480        .collect::<Result<Vec<_>, _>>()?;
481    let derive = (!derive.is_empty()).then(|| quote! {#[derive(#(#derive),*)]});
482
483    let k8s_openapi_impl_resource = attrs
484        .k8s_openapi
485        .as_ref()
486        .is_some_and(|attr| attr.resource.is_some())
487        .then(|| {
488            k8s_openapi_impl_resource(
489                &ty_ident,
490                &ty_ident_opt,
491                &impl_generics,
492                &ty_generics,
493                &where_clause_impl_optionable,
494            )
495        });
496    let impl_k8s_metadata = attrs
497        .k8s_openapi
498        .as_ref()
499        .is_some_and(|attr| attr.metadata.is_some())
500        .then(|| {
501            k8s_openapi_impl_metadata(
502                &ty_ident,
503                &ty_ident_opt,
504                &impl_generics,
505                &ty_generics,
506                &where_clause_impl_optionable,
507            )
508        });
509    let kube_derive_resource = attrs
510        .kube
511        .is_some_and(|attr| attr.resource.is_some())
512        .then(|| {
513            quote! {
514                #[derive(kube::Resource)]
515                #[resource(inherit = #ty_ident )]
516            }
517        });
518    Ok(quote! {
519                #derive
520                #kube_derive_resource
521                #ty_attr_forwarded
522                #k8s_openapi_attrs
523                #vis #enum_struct #ty_ident_opt #impl_generics #where_clause_struct_enum #fields
524
525                #[automatically_derived]
526                impl #impl_generics #crate_name::Optionable for #ty_ident #ty_generics #where_clause_impl_optionable {
527                    type Optioned = #ty_ident_opt #ty_generics;
528                }
529
530                #[automatically_derived]
531                impl #impl_generics #crate_name::Optionable for #ty_ident_opt #ty_generics #where_clause_impl_optionable {
532                    type Optioned = #ty_ident_opt #ty_generics;
533                }
534
535                #impl_optionable_convert
536
537                #k8s_openapi_impl_resource
538                #impl_k8s_metadata
539    })
540}
541
542/// Returns a tokenstream for the optioned fields and potential convert implementation of the optioned object (struct/enum variants).
543/// The returned tokenstream will be of the form `{...}` for named fields and `(...)` for unnamed fields.
544/// Does not include any leading `struct/enum` keywords or any trailing `;`.
545fn optioned_fields(
546    fields: &StructParsed,
547    serde_attributes: Option<&TokenStream>,
548    field_attr_forwards: &HashMap<Path, HashSet<Path>>,
549) -> Result<TokenStream, Error> {
550    let fields_token = fields.fields.iter().map(
551        |FieldParsed {
552             field: Field { attrs, vis, ident, ty, .. },
553             handling,
554         }| {
555            let forwarded_attrs = forwarded_attributes(attrs, field_attr_forwards)?;
556            let optioned_ty = optioned_ty(&fields.crate_name, ty);
557            let colon = ident.as_ref().map(|_| quote! {:});
558            Ok::<_, Error>(match handling {
559                FieldHandling::Required | FieldHandling::OptionedOnly => quote! {#forwarded_attrs #vis #ident #colon #ty},
560                FieldHandling::IsOption => quote! {#forwarded_attrs #serde_attributes #vis #ident #colon #optioned_ty},
561                FieldHandling::Other => quote! {#forwarded_attrs #serde_attributes #vis #ident #colon Option<#optioned_ty>},
562            })
563        },
564    ).collect::<Result<Vec<_>, _>>()?;
565    Ok(struct_wrapper(fields_token, &fields.struct_type))
566}
567
568/// Returns the field mapping implementation for `into_optioned`.
569/// The returned tokenstream will be of the form `{...}` for named fields and `(...)` for unnamed fields.
570/// Does not include any leading `struct/enum` keywords or any trailing `;`.
571fn into_optioned(
572    struct_parsed: &StructParsed,
573    self_selector_fn: impl Fn(&TokenStream) -> TokenStream,
574) -> TokenStream {
575    let fields_token = struct_parsed.fields.iter().enumerate().map(|(i, FieldParsed { field: Field { ident, ty, .. }, handling })| {
576        let colon = ident.as_ref().map(|_| quote! {:});
577        let selector = ident.as_ref().map_or_else(|| {
578            let i = Literal::usize_unsuffixed(i);
579            quote! {#i}
580        }, ToTokens::to_token_stream);
581        let self_selector = self_selector_fn(&selector);
582        let crate_name = &struct_parsed.crate_name;
583        match (handling, is_self_resolving_optioned(ty)) {
584            (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => quote! {#ident #colon #self_selector},
585            (FieldHandling::IsOption, false) => quote! {#ident #colon #crate_name::OptionableConvert::into_optioned(#self_selector)},
586            (FieldHandling::Other, true) => quote! {#ident #colon Some(#self_selector)},
587            (FieldHandling::Other, false) => quote! {#ident #colon Some(#crate_name::OptionableConvert::into_optioned(#self_selector))},
588            (FieldHandling::OptionedOnly, _) => quote! {#ident #colon Default::default()},
589        }
590    });
591    struct_wrapper(fields_token, &struct_parsed.struct_type)
592}
593
594/// Returns the field-mappings implementation for `try_from_optioned`.
595/// The returned tokenstream will be of the form `{...}` for named fields and `(...)` for unnamed fields.
596/// Does not include any leading `struct/enum` keywords or any trailing `;`.
597fn try_from_optioned(
598    struct_parsed: &StructParsed,
599    value_selector_fn: impl Fn(&TokenStream) -> TokenStream,
600) -> TokenStream {
601    let fields_token = struct_parsed.fields.iter().enumerate().map(|(i, FieldParsed { field: Field { ident, ty, .. }, handling })| {
602        let colon = ident.as_ref().map(|_| quote! {:});
603        let selector = ident.as_ref().map_or_else(|| {
604            let i = Literal::usize_unsuffixed(i);
605            quote! {#i}
606        }, ToTokens::to_token_stream);
607        let value_selector = value_selector_fn(&selector);
608        let crate_name = &struct_parsed.crate_name;
609        match (handling, is_self_resolving_optioned(ty)) {
610            (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => quote! {#ident #colon value.#selector},
611            (FieldHandling::IsOption, false) => quote! {
612                #ident #colon #crate_name::OptionableConvert::try_from_optioned(
613                    #value_selector
614                )?
615            },
616            (FieldHandling::Other, true) => {
617                let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
618                quote! {
619                    #ident #colon #value_selector.ok_or(#crate_name::Error{ missing_field: #selector_quoted })?
620                }
621            }
622            (FieldHandling::Other, false) => {
623                let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
624                quote! {
625                    #ident #colon #crate_name::OptionableConvert::try_from_optioned(#value_selector.ok_or(#crate_name::Error{ missing_field: #selector_quoted })?
626                    )?
627                }
628            }
629            (FieldHandling::OptionedOnly, _) => TokenStream::default(),
630        }
631    });
632
633    struct_wrapper(fields_token, &struct_parsed.struct_type)
634}
635
636/// Returns the field-mappings implementation for `try_from_optioned`.
637/// The returned tokenstream will be of the form `{...}` for named fields and `(...)` for unnamed fields.
638/// Does not include any leading `struct/enum` keywords or any trailing `;`.
639///
640/// `merge_self_mut` should be true when the `self_selector` merge argument should be modified with a `& mut` on recursive calls.
641fn merge_fields(
642    struct_parsed: &StructParsed,
643    self_selector_fn: impl Fn(&TokenStream) -> TokenStream,
644    other_selector_fn: impl Fn(&TokenStream) -> TokenStream,
645    merge_self_mut: bool,
646) -> TokenStream {
647    let fields_token = struct_parsed.fields.iter().enumerate().map(
648        |(
649             i,
650             FieldParsed {
651                 field: Field { ident, ty, .. },
652                 handling,
653             },
654         )| {
655            let selector = ident.as_ref().map_or_else(
656                || {
657                    let i = Literal::usize_unsuffixed(i);
658                    quote! {#i}
659                },
660                ToTokens::to_token_stream,
661            );
662            let self_merge_mut_modifier = merge_self_mut.then(|| quote! {&mut});
663            let deref_modifier = (!merge_self_mut).then(|| quote! {*});
664            let self_selector = self_selector_fn(&selector);
665            let other_selector = other_selector_fn(&selector);
666            let crate_name = &struct_parsed.crate_name;
667            match (handling, is_self_resolving_optioned(ty)) {
668                (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => quote! {#deref_modifier #self_selector = #other_selector;},
669                (FieldHandling::IsOption, false) => quote! {
670                    #crate_name::OptionableConvert::merge(#self_merge_mut_modifier #self_selector, #other_selector)?;
671                },
672                (FieldHandling::Other, true) => quote! {
673                    if let Some(other_value)=#other_selector{
674                        #deref_modifier #self_selector = other_value;
675                    }
676                },
677                (FieldHandling::Other, false) => quote! {
678                    if let Some(other_value)=#other_selector{
679                        #crate_name::OptionableConvert::merge(#self_merge_mut_modifier #self_selector, other_value)?;
680                    }
681                },
682                (FieldHandling::OptionedOnly, _) => TokenStream::default(),
683            }
684        },
685    );
686
687    quote! {
688        #(#fields_token)*
689    }
690}
691/// Tries to resolve the optioned type analogous to what we do in the main crate.
692/// Due to limitations to macro resolving (no order guaranteed) we have to have an explicit
693/// list of well-known types and their optioned types.
694/// For now limited to self-resolving (mostly primitive) types
695fn optioned_ty(crate_name: &Path, ty: &Type) -> TokenStream {
696    if is_self_resolving_optioned(ty) {
697        ty.to_token_stream()
698    } else {
699        quote! { <#ty as #crate_name::Optionable>::Optioned }
700    }
701}
702
703const SELF_RESOLVING_TYPES: [&str; 18] = [
704    // Rust primitives don't have inner structure, https://doc.rust-lang.org/rust-by-example/primitives.html
705    "i8", "i16", "i32", "i64", "i128", "isize", "u8", "u16", "u32", "u64", "u128", "usize", "f32",
706    "f64", "char", "bool", // Other types without inner structure
707    "String", "OsString",
708];
709
710/// Checks when it is well known that the type resolves to itself as its `Optioned`.
711/// Limited to self-resolving (mostly primitive) types.
712fn is_self_resolving_optioned(ty: &Type) -> bool {
713    if let Type::Path(TypePath { qself, path }) = &ty
714        && qself.is_none()
715        && SELF_RESOLVING_TYPES.contains(&&*path.to_token_stream().to_string())
716    {
717        true
718    } else {
719        false
720    }
721}
722
723/// Extracts the `HELPER_ATTR_IDENT` attributes, unwraps them and returns them
724/// as `TokenStream` that can be used as respective attribute.
725fn forwarded_attributes(
726    attrs: &[Attribute],
727    attr_to_copy: &HashMap<Path, HashSet<Path>>,
728) -> Result<Option<TokenStream>, Error> {
729    let forward_attrs = attrs
730        .iter()
731        .map(|attr| {
732            if attr.path().is_ident(HELPER_ATTR_IDENT) {
733                return match &attr.meta {
734                    Meta::List(MetaList { tokens, .. }) => Ok(Some(quote!(#[#tokens]))),
735                    _ => error("Only lists like `#[optionable_attr(Serialize,Deserialize)]` are supported for `optionable_attr`"),
736                };
737            }
738            let keys_to_copy=attr_to_copy.get(attr.path());
739            if let Some(keys_to_copy)=keys_to_copy{
740                // no key restrictions
741                if keys_to_copy.is_empty(){
742                    if attr.path().is_ident("derive")&& let   Meta::List(meta_list)=&attr.meta{
743                        let derives=Punctuated::<Path, Token![,]>::parse_terminated
744                            .parse2(meta_list.tokens.clone())?.into_iter().filter(|el|el.to_token_stream().to_string()!="Optionable"&&el.to_token_stream().to_string()!="optionable::Optionable");
745                        return Ok(Some(quote! {#[derive(#(#derives,)*)]}));
746                    }
747                    Ok(Some(attr.to_token_stream()))
748                } else{
749                    match &attr.meta{
750                        Meta::Path(_) => Ok(None),
751                        Meta::NameValue(meta_name_value) => Ok(keys_to_copy.contains(&meta_name_value.path).then(|| attr.to_token_stream())),
752                        Meta::List(meta_list) => {
753                            // we support one level of nesting for a Meta::List(Meta::NameValue(..)) setup like it's used by #[serde(rename=...)]
754                            let inner_metas :Vec<TokenStream>= Punctuated::<Meta, Token![,]>::parse_terminated
755                                .parse2(meta_list.tokens.clone())?.into_iter().filter_map(|meta|{
756                                if let Meta::NameValue(meta_name_value)= meta{
757                                    keys_to_copy.contains(&meta_name_value.path).then(|| Ok::<_,Error>(meta_name_value.to_token_stream()))
758                                } else{
759                                    None
760                                }
761                            }).collect::<Result<_,_>>()?;
762                            if inner_metas.is_empty() {
763                                Ok(None)
764                            } else {
765                                let mut attr=attr.clone();
766                                let mut meta_list=meta_list.clone();
767                                meta_list.tokens=inner_metas.into_iter().collect();
768                                attr.meta=meta_list.into();
769                                Ok(Some(attr.to_token_stream()))
770                            }
771                        }
772                    }
773                }
774            } else{
775                Ok(None)
776            }
777        })
778        .collect::<Result<Vec<_>,_>>()?
779        .into_iter()
780        .flatten()
781        .collect::<TokenStream>();
782    Ok((!forward_attrs.is_empty()).then_some(forward_attrs))
783}
784
785#[cfg(test)]
786mod tests {
787    use crate::{derive_optionable, CodegenSettings};
788    use darling::FromMeta;
789    use proc_macro2::TokenStream;
790    use quote::quote;
791    use syn::{parse_quote, Path};
792
793    struct TestCase {
794        input: TokenStream,
795        output: TokenStream,
796    }
797
798    #[test]
799    #[allow(clippy::too_many_lines)]
800    fn test_optionable() {
801        let tcs = vec![
802            // named struct fields
803            TestCase {
804                input: quote! {
805                    #[derive(Optionable)]
806                    struct DeriveExample {
807                        name: String,
808                        pub surname: String,
809                    }
810                },
811                output: quote! {
812                    struct DeriveExampleOpt {
813                        name: Option<String>,
814                        pub surname: Option<String>
815                    }
816
817                    #[automatically_derived]
818                    impl ::optionable::Optionable for DeriveExample {
819                        type Optioned = DeriveExampleOpt;
820                    }
821
822                    #[automatically_derived]
823                    impl ::optionable::Optionable for DeriveExampleOpt {
824                        type Optioned = DeriveExampleOpt;
825                    }
826
827                    #[automatically_derived]
828                    impl ::optionable::OptionableConvert for DeriveExample {
829                        fn into_optioned (self) -> DeriveExampleOpt {
830                            DeriveExampleOpt  {
831                                name: Some(self.name),
832                                surname:Some(self.surname)
833                            }
834                        }
835
836                        fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
837                            Ok(Self{
838                                name: value.name.ok_or(::optionable::Error { missing_field: "name" })?,
839                                surname: value.surname.ok_or(::optionable::Error { missing_field: "surname" })?
840                            })
841                        }
842
843                        fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
844                            if let Some(other_value) = other.name {
845                                self.name = other_value;
846                            }
847                            if let Some(other_value) = other.surname {
848                                self.surname = other_value;
849                            }
850                            Ok(())
851                        }
852                    }
853                },
854            },
855            // named struct fields, no convert impl
856            TestCase {
857                input: quote! {
858                    #[derive(Optionable)]
859                    #[optionable(no_convert)]
860                    struct DeriveExample {
861                        name: String,
862                        pub surname: String,
863                    }
864                },
865                output: quote! {
866                    struct DeriveExampleOpt {
867                        name: Option<String>,
868                        pub surname: Option<String>
869                    }
870
871                    #[automatically_derived]
872                    impl ::optionable::Optionable for DeriveExample {
873                        type Optioned = DeriveExampleOpt;
874                    }
875
876                    #[automatically_derived]
877                    impl ::optionable::Optionable for DeriveExampleOpt {
878                        type Optioned = DeriveExampleOpt;
879                    }
880                },
881            },
882            // named struct fields with required fields
883            TestCase {
884                input: quote! {
885                    #[derive(Optionable)]
886                    struct DeriveExample {
887                        name: String,
888                        #[optionable(required)]
889                        pub surname: String,
890                    }
891                },
892                output: quote! {
893                    struct DeriveExampleOpt {
894                        name: Option<String>,
895                        pub surname: String
896                    }
897
898                    #[automatically_derived]
899                    impl ::optionable::Optionable for DeriveExample {
900                        type Optioned = DeriveExampleOpt;
901                    }
902
903                    #[automatically_derived]
904                    impl ::optionable::Optionable for DeriveExampleOpt {
905                        type Optioned = DeriveExampleOpt;
906                    }
907
908                    #[automatically_derived]
909                    impl ::optionable::OptionableConvert for DeriveExample {
910                        fn into_optioned (self) -> DeriveExampleOpt {
911                            DeriveExampleOpt  {
912                                name: Some(self.name),
913                                surname: self.surname
914                            }
915                        }
916
917                        fn try_from_optioned(value:DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
918                            Ok (Self {
919                                name: value.name.ok_or(::optionable::Error { missing_field: "name" })?,
920                                surname: value.surname
921                            })
922                        }
923
924                        fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
925                            if let Some(other_value) = other.name {
926                                self.name = other_value;
927                            }
928                            self.surname = other.surname;
929                            Ok (())
930                        }
931                    }
932                },
933            },
934            // named struct fields with forwarded derives and Serialize annotations
935            TestCase {
936                input: quote! {
937                    #[derive(Optionable)]
938                    #[optionable(derive(Deserialize,Serialize,Default),suffix="Ac")]
939                    #[optionable(attr_copy(attr=serde,key=rename))]
940                    #[optionable_attr(serde(rename_all = "camelCase", deny_unknown_fields))]
941                    #[optionable_attr(serde(default))]
942                    struct DeriveExample {
943                        #[optionable_attr(serde(rename = "firstName"))]
944                        name: String,
945                        #[serde(rename="middle__name")]
946                        middle_name: Option<String>,
947                        surname: String,
948                    }
949                },
950                output: quote! {
951                    #[derive(Default, Deserialize, Serialize)]
952                    #[serde(rename_all = "camelCase", deny_unknown_fields)]
953                    #[serde(default)]
954                    struct DeriveExampleAc {
955                        #[serde(rename = "firstName")]
956                        #[serde(skip_serializing_if = "Option::is_none")]
957                        name: Option<String>,
958                        #[serde(rename = "middle__name")]
959                        #[serde(skip_serializing_if = "Option::is_none")]
960                        middle_name: <Option<String> as ::optionable::Optionable>::Optioned,
961                        #[serde(skip_serializing_if = "Option::is_none")]
962                        surname: Option<String>
963                    }
964
965                    #[automatically_derived]
966                    impl ::optionable::Optionable for DeriveExample {
967                        type Optioned = DeriveExampleAc;
968                    }
969
970                    #[automatically_derived]
971                    impl ::optionable::Optionable for DeriveExampleAc {
972                        type Optioned = DeriveExampleAc;
973                    }
974
975                    #[automatically_derived]
976                    impl ::optionable::OptionableConvert for DeriveExample {
977                        fn into_optioned (self) -> DeriveExampleAc {
978                            DeriveExampleAc  {
979                                name: Some(self.name),
980                                middle_name: ::optionable::OptionableConvert::into_optioned(self.middle_name),
981                                surname: Some(self.surname)
982                            }
983                        }
984
985                        fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::Error> {
986                            Ok(Self{
987                                name: value.name.ok_or(::optionable::Error { missing_field: "name"})?,
988                                middle_name: ::optionable::OptionableConvert::try_from_optioned(value.middle_name)?,
989                                surname: value.surname.ok_or(::optionable::Error { missing_field: "surname"})?
990                            })
991                        }
992
993                        fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::Error> {
994                            if let Some(other_value) = other.name {
995                                self.name =  other_value;
996                            }
997                            ::optionable::OptionableConvert::merge(&mut self.middle_name, other.middle_name)?;
998                            if let Some(other_value) = other.surname {
999                                self.surname =  other_value;
1000                            }
1001                            Ok(())
1002                        }
1003                    }
1004                },
1005            },
1006            // named struct fields with forwarded derives and Serialize annotations (full path variant)
1007            TestCase {
1008                input: quote! {
1009                    #[derive(Optionable)]
1010                    #[optionable(derive(serde::Deserialize,serde::Serialize),suffix="Ac")]
1011                    struct DeriveExample {
1012                        name: String,
1013                        surname: String,
1014                    }
1015                },
1016                output: quote! {
1017                    #[derive(serde::Deserialize, serde::Serialize)]
1018                    struct DeriveExampleAc {
1019                        #[serde(skip_serializing_if = "Option::is_none")]
1020                        name: Option<String>,
1021                        #[serde(skip_serializing_if = "Option::is_none")]
1022                        surname: Option<String>
1023                    }
1024
1025                    #[automatically_derived]
1026                    impl ::optionable::Optionable for DeriveExample {
1027                        type Optioned = DeriveExampleAc;
1028                    }
1029
1030                    #[automatically_derived]
1031                    impl ::optionable::Optionable for DeriveExampleAc {
1032                        type Optioned = DeriveExampleAc;
1033                    }
1034
1035                    #[automatically_derived]
1036                    impl ::optionable::OptionableConvert for DeriveExample {
1037                        fn into_optioned (self) -> DeriveExampleAc {
1038                            DeriveExampleAc {
1039                                name: Some(self.name),
1040                                surname: Some(self.surname)
1041                            }
1042                        }
1043
1044                        fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::Error> {
1045                             Ok(Self{
1046                                name: value.name.ok_or(::optionable::Error{ missing_field: "name"})?,
1047                                surname: value.surname.ok_or(::optionable::Error{ missing_field: "surname"})?
1048                            })
1049                        }
1050
1051                        fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::Error> {
1052                            if let Some(other_value) = other.name {
1053                                self.name = other_value;
1054                            }
1055                            if let Some(other_value) = other.surname {
1056                                self.surname = other_value;
1057                            }
1058                            Ok(())
1059                        }
1060                    }
1061                },
1062            },
1063            // unnamed struct fields
1064            TestCase {
1065                input: quote! {
1066                    #[derive(Optionable)]
1067                    struct DeriveExample(pub String, i32);
1068                },
1069                output: quote! {
1070                    struct DeriveExampleOpt(
1071                        pub Option<String>,
1072                        Option<i32>
1073                    );
1074
1075                    #[automatically_derived]
1076                    impl ::optionable::Optionable for DeriveExample {
1077                        type Optioned = DeriveExampleOpt;
1078                    }
1079
1080                    #[automatically_derived]
1081                    impl ::optionable::Optionable for DeriveExampleOpt {
1082                        type Optioned = DeriveExampleOpt;
1083                    }
1084
1085                    #[automatically_derived]
1086                    impl ::optionable::OptionableConvert for DeriveExample {
1087                        fn into_optioned (self) -> DeriveExampleOpt {
1088                            DeriveExampleOpt (
1089                                Some(self.0),
1090                                Some(self.1)
1091                            )
1092                        }
1093
1094                         fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
1095                            Ok(Self(
1096                                value.0.ok_or(::optionable::Error { missing_field:"0" })?,
1097                                value.1.ok_or(::optionable::Error { missing_field: "1" })?
1098                            ))
1099                        }
1100
1101                        fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
1102                            if let Some(other_value) = other.0 {
1103                                self.0 = other_value;
1104                            }
1105                            if let Some (other_value) = other.1 {
1106                                self.1 = other_value;
1107                            }
1108                            Ok (())
1109                        }
1110                    }
1111                },
1112            },
1113            // unnamed struct fields with required
1114            TestCase {
1115                input: quote! {
1116                    #[derive(Optionable)]
1117                    struct DeriveExample(pub String, #[optionable(required)] i32);
1118                },
1119                output: quote! {
1120                    struct DeriveExampleOpt(
1121                        pub Option<String>,
1122                        i32
1123                    );
1124
1125                    #[automatically_derived]
1126                    impl ::optionable::Optionable for DeriveExample {
1127                        type Optioned = DeriveExampleOpt;
1128                    }
1129
1130                    #[automatically_derived]
1131                    impl ::optionable::Optionable for DeriveExampleOpt {
1132                        type Optioned = DeriveExampleOpt;
1133                    }
1134
1135                    # [automatically_derived]
1136                    impl ::optionable::OptionableConvert for DeriveExample {
1137                        fn into_optioned (self) -> DeriveExampleOpt {
1138                            DeriveExampleOpt (
1139                                Some(self.0),
1140                                self.1
1141                            )
1142                        }
1143
1144                         fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
1145                            Ok(Self(
1146                                value.0.ok_or(::optionable::Error { missing_field: "0" })?,
1147                                value.1))
1148                        }
1149
1150                        fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
1151                            if let Some(other_value) = other.0 {
1152                                self.0 = other_value;
1153                            }
1154                            self.1 = other.1;
1155                            Ok (())
1156                        }
1157                    }
1158                },
1159            },
1160            // named struct fields with generics
1161            TestCase {
1162                input: quote! {
1163                    #[derive(Optionable)]
1164                    #[optionable(derive(Serialize, Deserialize))]
1165                    struct DeriveExample<T, T2: Serialize, T3> {
1166                        output: T,
1167                        input: T2,
1168                        #[optionable(required)]
1169                        extra: T3,
1170                    }
1171                },
1172                output: quote! {
1173                    #[derive (Deserialize, Serialize)]
1174                    struct DeriveExampleOpt<T, T2: Serialize, T3>
1175                        where T: ::optionable::Optionable,
1176                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1177                              T2: ::optionable::Optionable,
1178                              <T2 as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1179                    {
1180                        #[serde(skip_serializing_if="Option::is_none")]
1181                        output: Option< <T as ::optionable::Optionable>::Optioned>,
1182                        #[serde(skip_serializing_if="Option::is_none")]
1183                        input: Option< <T2 as ::optionable::Optionable>::Optioned>,
1184                        extra: T3
1185                    }
1186
1187                    #[automatically_derived]
1188                    impl<T, T2: Serialize, T3> ::optionable::Optionable for DeriveExample<T, T2, T3>
1189                        where T: ::optionable::Optionable,
1190                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1191                              T2: ::optionable::Optionable,
1192                              <T2 as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1193                    {
1194                        type Optioned = DeriveExampleOpt<T,T2,T3>;
1195                    }
1196
1197                    #[automatically_derived]
1198                    impl<T, T2: Serialize, T3> ::optionable::Optionable for DeriveExampleOpt<T, T2, T3>
1199                        where T: ::optionable::Optionable,
1200                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1201                              T2: ::optionable::Optionable,
1202                              <T2 as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1203                    {
1204                        type Optioned = DeriveExampleOpt<T, T2, T3>;
1205                    }
1206
1207                    #[automatically_derived]
1208                    impl <T, T2:Serialize, T3> ::optionable::OptionableConvert for DeriveExample<T, T2, T3>
1209                        where T: ::optionable::OptionableConvert,
1210                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1211                              T2: ::optionable::OptionableConvert,
1212                              <T2 as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1213                    {
1214                        fn into_optioned (self) -> DeriveExampleOpt<T, T2, T3> {
1215                            DeriveExampleOpt::<T, T2, T3> {
1216                                output: Some(::optionable::OptionableConvert::into_optioned(self.output)),
1217                                input: Some(::optionable::OptionableConvert::into_optioned(self.input)),
1218                                extra: self.extra
1219                            }
1220                        }
1221
1222                         fn try_from_optioned(value: DeriveExampleOpt<T, T2, T3> ) -> Result <Self, ::optionable::Error> {
1223                             Ok(Self{
1224                                output: ::optionable::OptionableConvert::try_from_optioned(value.output.ok_or(::optionable::Error { missing_field: "output" })?)?,
1225                                input: ::optionable::OptionableConvert::try_from_optioned(value.input.ok_or(::optionable::Error { missing_field: "input" })?)?,
1226                                extra: value.extra
1227                            })
1228                        }
1229
1230                        fn merge(&mut self, other: DeriveExampleOpt<T, T2, T3> ) -> Result<(), ::optionable::Error> {
1231                            if let Some(other_value) = other.output {
1232                                ::optionable::OptionableConvert::merge(&mut self.output, other_value)?;
1233                            }
1234                            if let Some(other_value) = other.input {
1235                                ::optionable::OptionableConvert::merge(&mut self.input, other_value)?;
1236                            }
1237                            self.extra=other.extra;
1238                            Ok(())
1239                        }
1240                    }
1241                },
1242            },
1243            TestCase {
1244                input: quote! {
1245                    #[derive(Optionable)]
1246                    enum DeriveExample {
1247                        Unit,
1248                        Plain(String),
1249                        Address{street: String, number: u32},
1250                        Address2(String,u32),
1251                    }
1252                },
1253                output: quote! {
1254                    enum DeriveExampleOpt {
1255                        Unit,
1256                        Plain( Option<String> ),
1257                        Address{ street: Option<String>, number:Option<u32> },
1258                        Address2( Option<String>, Option<u32> )
1259                    }
1260
1261                    #[automatically_derived]
1262                    impl ::optionable::Optionable for DeriveExample {
1263                        type Optioned = DeriveExampleOpt;
1264                    }
1265
1266                    #[automatically_derived]
1267                    impl ::optionable::Optionable for DeriveExampleOpt {
1268                        type Optioned = DeriveExampleOpt;
1269                    }
1270
1271                    #[automatically_derived]
1272                    impl ::optionable::OptionableConvert for DeriveExample {
1273                        fn into_optioned (self) -> DeriveExampleOpt {
1274                            match self{
1275                                Self::Unit => DeriveExampleOpt::Unit,
1276                                Self::Plain(self_0) => DeriveExampleOpt::Plain(
1277                                    Some(self_0)
1278                                ),
1279                                Self::Address{street: self_street, number: self_number} => DeriveExampleOpt::Address{
1280                                    street: Some(self_street),
1281                                    number: Some(self_number)
1282                                },
1283                                Self::Address2(self_0, self_1) => DeriveExampleOpt::Address2(
1284                                    Some(self_0),
1285                                    Some(self_1)
1286                                )
1287                            }
1288                        }
1289
1290                         fn try_from_optioned(other: DeriveExampleOpt) -> Result <Self, ::optionable::Error> {
1291                            Ok (match other {
1292                                DeriveExampleOpt::Unit => Self::Unit,
1293                                DeriveExampleOpt::Plain(other_0) => Self::Plain(
1294                                    other_0.ok_or(::optionable::Error { missing_field: "0" })?
1295                                ),
1296                                DeriveExampleOpt::Address{street: other_street, number: other_number} => Self::Address{
1297                                    street: other_street.ok_or(::optionable::Error { missing_field: "street" })?,
1298                                    number: other_number.ok_or(::optionable::Error { missing_field: "number" })?
1299                                },
1300                                DeriveExampleOpt::Address2(other_0, other_1) => Self::Address2(
1301                                    other_0.ok_or(::optionable::Error { missing_field: "0"})?,
1302                                    other_1.ok_or(::optionable::Error { missing_field: "1"})?)
1303                            })
1304                        }
1305
1306                        fn merge(&mut self, other: DeriveExampleOpt) -> Result<(), ::optionable::Error> {
1307                            match other {
1308                                DeriveExampleOpt::Unit => {
1309                                    if let Self::Unit = self {} else {
1310                                        *self = Self::try_from_optioned(DeriveExampleOpt::Unit)?;
1311                                    }
1312                                },
1313                                DeriveExampleOpt::Plain(other_0) => {
1314                                    if let Self::Plain(self_0) = self{
1315                                        if let Some(other_value) = other_0 {
1316                                            *self_0 = other_value;
1317                                        }
1318                                    } else {
1319                                        *self = Self::try_from_optioned(DeriveExampleOpt::Plain(other_0))?;
1320                                    }
1321                                },
1322                                DeriveExampleOpt::Address{street: other_street, number: other_number} => {
1323                                    if let Self::Address{street: self_street, number: self_number}  = self{
1324                                        if let Some(other_value) = other_street {
1325                                            *self_street = other_value;
1326                                        }
1327                                        if let Some(other_value) = other_number {
1328                                            *self_number = other_value;
1329                                        }
1330                                    } else {
1331                                        *self = Self::try_from_optioned(DeriveExampleOpt::Address{street: other_street, number: other_number})?;
1332                                    }
1333                                },
1334                                DeriveExampleOpt::Address2(other_0, other_1) => {
1335                                    if let Self::Address2(self_0, self_1) = self{
1336                                        if let Some(other_value) = other_0 {
1337                                            *self_0 = other_value;
1338                                        }
1339                                        if let Some(other_value) = other_1 {
1340                                            *self_1 = other_value;
1341                                        }
1342                                    } else {
1343                                        *self = Self::try_from_optioned(DeriveExampleOpt::Address2(other_0, other_1))?;
1344                                    }
1345                                }
1346                            }
1347                            Ok(())
1348                        }
1349                    }
1350                },
1351            },
1352        ];
1353        for tc in tcs {
1354            let input = syn::parse2(tc.input).unwrap();
1355            let output = derive_optionable(input, None).unwrap();
1356            println!("{output}");
1357            assert_eq!(tc.output.to_string(), output.to_string());
1358        }
1359    }
1360
1361    #[test]
1362    #[allow(clippy::too_many_lines)]
1363    /// Tests of the crate replacement settings available via codegen settings only
1364    fn test_crate_replacement() {
1365        let tcs = vec![TestCase {
1366            input: quote! {
1367                #[derive(Optionable)]
1368                struct DeriveExample {
1369                    name: crate::Name,
1370                    pub surname: Box<crate::SurName>,
1371                }
1372            },
1373            output: quote! {
1374                struct DeriveExampleOpt {
1375                    name: Option< <::testcrate::Name as crate::Optionable>::Optioned>,
1376                    pub surname: Option< <Box<::testcrate::SurName> as crate::Optionable>::Optioned>
1377                }
1378
1379                #[automatically_derived]
1380                impl crate::Optionable for crate_prefix::DeriveExample {
1381                    type Optioned = DeriveExampleOpt;
1382                }
1383
1384                #[automatically_derived]
1385                impl crate::Optionable for DeriveExampleOpt {
1386                    type Optioned = DeriveExampleOpt;
1387                }
1388
1389                #[automatically_derived]
1390                impl crate::OptionableConvert for crate_prefix::DeriveExample {
1391                    fn into_optioned (self) -> DeriveExampleOpt {
1392                        DeriveExampleOpt  {
1393                            name: Some(crate::OptionableConvert::into_optioned(self.name)),
1394                            surname: Some(crate::OptionableConvert::into_optioned(self.surname))
1395                        }
1396                    }
1397
1398                    fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, crate::Error> {
1399                        Ok(Self{
1400                            name: crate::OptionableConvert::try_from_optioned(value.name.ok_or(crate::Error { missing_field: "name" })?)?,
1401                            surname: crate::OptionableConvert::try_from_optioned(value.surname.ok_or(crate::Error { missing_field: "surname" })?)?
1402                        })
1403                    }
1404
1405                    fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), crate::Error> {
1406                        if let Some(other_value) = other.name {
1407                             crate::OptionableConvert::merge(&mut self.name, other_value)?;
1408                        }
1409                        if let Some(other_value) = other.surname {
1410                             crate::OptionableConvert::merge(&mut self.surname, other_value)?;
1411                        }
1412                        Ok(())
1413                    }
1414                }
1415            },
1416        }];
1417        for tc in tcs {
1418            let input = syn::parse2(tc.input).unwrap();
1419            let output = derive_optionable(
1420                input,
1421                Some(&CodegenSettings {
1422                    ty_prefix: Some(Path::from_string("crate_prefix").unwrap()),
1423                    optionable_crate_name: Path::from_string("crate").unwrap(),
1424                    input_crate_replacement: Some(parse_quote!(testcrate)),
1425                }),
1426            )
1427            .unwrap();
1428            assert_eq!(tc.output.to_string(), output.to_string());
1429        }
1430    }
1431}