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