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 std::mem::take;
36use syn::parse::Parser;
37use syn::punctuated::Punctuated;
38use syn::spanned::Spanned;
39use syn::{
40    parse_quote, Attribute, Data, DeriveInput, Error, Field, Fields, LitStr, Meta, MetaList, Path, Token,
41    Type, TypePath, WhereClause,
42};
43
44const HELPER_IDENT: &str = "optionable";
45const HELPER_ATTR_IDENT: &str = "optionable_attr";
46const ERR_MSG_HELPER_ATTR_ENUM_VARIANTS: &str =
47    "#[optionable] helper attributes not supported on enum variant level.";
48
49#[derive(FromDeriveInput)]
50#[darling(attributes(optionable))]
51/// Helper attributes on the type definition level (attached to the `struct` or `enum` itself).
52pub(crate) struct TypeHelperAttributes {
53    /// Forwards the specified `attr` to the definition of the optioned type.
54    /// If any `key` is set it filters the configuration of the forwarded attributes for the specified configuration names.
55    /// E.g. `#[optionable(attr_copy(attr=serde,key=rename)]` will only forward the `rename`sub-attribute of serde.
56    #[darling(multiple)]
57    attr_copy: Vec<FieldAttributeToCopy>,
58    /// Derive-macros that should be added to the optioned type
59    #[darling(multiple)]
60    derive: Vec<PathList>,
61    /// Explicit suffix to use for the optioned type.
62    suffix: Option<LitStr>,
63    /// Skip generating `OptionableConvert` impl
64    no_convert: Option<()>,
65    /// Wrap a field that is already an `Option<T>` inside an outer `Option<Option<T>>` for the optioned type.
66    /// Useful for struct patching but not helpful once serializing to e.g. JSON is involved.
67    option_wrap: Option<()>,
68    /// Adjustments of the derived optioned type for fields that use the `k8s_openapi` serialization replacements.
69    /// - Derives for the optioned type `Clone, Debug, PartialEq, Serialize, Deserialize` and additionally for Structs `Default`.
70    /// - Takes the `k8s_openapi` serialization replacements into account for its own serialization.
71    k8s_openapi: Option<TypeHelperAttributesK8sOpenapi>,
72    /// Adjustments of the derived optioned type for structs that `kube::CustomResource` or respective subfields.
73    /// - Derives for the optioned type `Clone, Debug, PartialEq, Serialize, Deserialize` and additionally for Structs `Default`.
74    /// - Sets `#[serde(rename_all="camelCase",deny_unknown_fields)]`
75    /// - Copy `#[(serde(rename="...")]` and `#[(serde(rename_all="...")]` attributes over to the optioned types.
76    kube: Option<TypeHelperAttributesKube>,
77}
78
79#[derive(FromMeta)]
80/// Adjustments of the derived optioned type for fields that use the `k8s_openapi` serialization replacements.
81/// - Derives for the optioned type `Clone, Debug, PartialEq, Serialize, Deserialize` and additionally for Structs `Default`.
82/// -
83/// - Takes the `k8s_openapi` serialization replacements into account for its own serialization.
84pub(crate) struct TypeHelperAttributesK8sOpenapi {
85    /// Adjustments of the derived optioned type for `k8s_openapi::Metadata`-implementations.
86    /// - Sets the `metadata` field as required for the optioned type.
87    /// - Derives `k8s_openapi::Metadata` for the optioned type.
88    metadata: Option<()>,
89    /// Adjustments of the derived optioned type for `k8s_openapi::Resource`-implementations.
90    /// - Adds `apiVersion` and `kind` to the serialization output with values from the trait constants of the given `k8s_openapi::Resource` implementation
91    /// - Derives `k8s_openapi::resource` for the optioned type.
92    resource: Option<()>,
93}
94
95#[derive(FromMeta)]
96/// Adjustments of the derived optioned type for structs that `kube::CustomResource` or respective subfields.
97/// - Derives for the optioned type `Clone, Debug, PartialEq, Serialize, Deserialize` and additionally for Structs `Default`.
98pub(crate) struct TypeHelperAttributesKube {
99    /// Adjustments of the derived optioned type for `kube::Resource`-implementations.
100    /// - Sets the `metadata` field as required for the optioned type.
101    /// - Adds `apiVersion` and `kind` to the serialization output with values from the trait constants of the given `kube::Resource` implementation
102    /// - Derives `kube::Resource` for the optioned type.
103    resource: Option<()>,
104}
105
106#[derive(FromMeta)]
107/// Forwards the specified `attr` to the definition of the optioned type.
108/// If `sub_names` is set it filters the configuration of the forwarded attribure for the specified configuration names.
109/// E.g. `attr=serde,sub_names=rename` will only forward the `rename`sub-attribute of serde.
110pub struct FieldAttributeToCopy {
111    pub attr: Path,
112    pub key: Option<Path>,
113}
114
115#[derive(FromAttributes)]
116#[darling(attributes(optionable))]
117/// Helper attributes on the type definition level (attached to the `struct` or `enum` itself).
118struct FieldHelperAttributes {
119    /// Given field won't be optioned, it will also be required for the derived optioned type.
120    required: Option<()>,
121    /// For circumvention of the orphan rule. Uses the provided type for the optioned variant of the field.
122    /// If `no_convert` is not set the provided type has to implement `OptionedConvert<O>` where `O` is the type of this field in the original type.
123    #[darling(rename = "optioned_type")]
124    optioned_ty: Option<Path>,
125}
126
127#[derive(FromDeriveInput, Debug, Clone)]
128#[darling(attributes(optionable))]
129/// Settings that are only available to be set via the rust function signature of `derive_optionable`
130/// but not via the derive macro (as they are not useful in that context and would lead to an
131/// increased but not useful API surface of the derive macro helpers).
132pub struct CodegenSettings {
133    /// Name of the optionable crate to use for the generated code including potentially
134    /// leading `::`. Useful to set when generating code for the `optionable`
135    /// crate itself where one needs to refer to it as `crate`.
136    pub optionable_crate_name: Path,
137    /// Path prefix to prepend to the respective type. E.g. with a `ty_prefix` of `::mycrate`
138    /// the output would be (simplified) `impl Optionable for ::mycrate::mytype`.
139    pub ty_prefix: Option<Path>,
140    /// Replacement for the keyword `crate` in the input type/enum definition or references.
141    /// Useful when generating code for the `optionable` crate as pre-existing `crate` references
142    /// need to be replaced with the concret crate name.
143    pub input_crate_replacement: Option<Ident>,
144}
145
146/// Processes the input field attribute forwards to a `HashMap`.
147/// Adds `attr=serde,key=rename` if the `kube` input attribute is present.
148fn field_attr_copy_hashmap(
149    input: Vec<FieldAttributeToCopy>,
150    attr_kube: Option<&TypeHelperAttributesKube>,
151) -> HashMap<Path, HashSet<Path>> {
152    let mut result = HashMap::<Path, HashSet<Path>>::new();
153    for el in input {
154        if let Some(key) = el.key {
155            if let Some(entry) = result.get_mut(&el.attr) {
156                entry.insert(key);
157            } else {
158                result.insert(el.attr, HashSet::from([key]));
159            }
160        }
161    }
162    if attr_kube.is_some() {
163        let path_serde = Path::from_string("serde").unwrap();
164        let path_rename = Path::from_string("rename").unwrap();
165        let path_rename_all = Path::from_string("rename_all").unwrap();
166        let path_rename_all_fields = Path::from_string("rename_all_fields").unwrap();
167        if let Some(entry) = result.get_mut(&path_serde) {
168            // If the keys are empty everything will be copied, so don't restrict it here
169            if !entry.is_empty() {
170                entry.insert(path_rename);
171                entry.insert(path_rename_all);
172            }
173        } else {
174            result.insert(
175                path_serde,
176                HashSet::from([path_rename, path_rename_all, path_rename_all_fields]),
177            );
178        }
179    }
180    result
181}
182
183impl Default for CodegenSettings {
184    fn default() -> Self {
185        Self {
186            optionable_crate_name: parse_quote!(::optionable),
187            ty_prefix: None,
188            input_crate_replacement: None,
189        }
190    }
191}
192
193/// Returns the attribute for opting-out of `OptionableConvert`-impl generation.
194#[must_use]
195pub fn attribute_no_convert() -> Attribute {
196    parse_quote!(#[optionable(no_convert)])
197}
198
199/// Returns the attribute for setting a custom struct/enum name suffix instead of `Opt`.
200#[must_use]
201pub fn attribute_suffix(suffix: &str) -> Attribute {
202    parse_quote!(#[optionable(suffix=#suffix)])
203}
204
205/// Returns the attribute for setting that the given identifiers should be added as
206/// derive macro to the optioned struct/enum.
207#[must_use]
208pub fn attribute_derives(derives: &PathList) -> Attribute {
209    parse_quote!(#[optionable(derive(#(#derives),*))])
210}
211
212/// Derives the `Optionable`-trait from the main `optionable`-library.
213///
214/// # Errors
215/// - on misplaced helper attributes
216/// - internal implementation errors
217#[allow(clippy::too_many_lines)]
218#[allow(clippy::items_after_statements)]
219pub fn derive_optionable(
220    input: DeriveInput,
221    settings: Option<&CodegenSettings>,
222) -> syn::Result<TokenStream> {
223    let settings = settings.map(Cow::Borrowed).unwrap_or_default();
224    let crate_name = &settings.optionable_crate_name;
225    let TypeHelperAttributes {
226        attr_copy,
227        derive: attr_derive,
228        suffix: attr_suffix,
229        no_convert: attr_no_convert,
230        option_wrap: attr_option_wrap,
231        k8s_openapi: attr_k8s_openapi,
232        kube: attr_kube,
233    } = TypeHelperAttributes::from_derive_input(&input)?;
234    let DeriveInput {
235        attrs,
236        vis,
237        mut generics,
238        data,
239        ..
240    } = input;
241    error_missing_features(attr_k8s_openapi.as_ref(), attr_kube.as_ref())?;
242
243    let ty_ident_opt = {
244        let suffix = attr_suffix.map_or_else(
245            || {
246                if attr_kube.is_some() || attr_k8s_openapi.is_some() {
247                    Cow::Borrowed("Ac")
248                } else {
249                    Cow::Borrowed("Opt")
250                }
251            },
252            |s| Cow::Owned(s.value()),
253        );
254        format_ident!("{}{suffix}", &input.ident)
255    };
256    let ty_ident = if let Some(mut ty_prefix) = settings.ty_prefix.clone() {
257        ty_prefix.segments.push(input.ident.into());
258        ty_prefix
259    } else {
260        input.ident.into()
261    };
262    if let Data::Enum(e) = &data
263        && e.variants
264            .iter()
265            .all(|el| matches!(el.fields, Fields::Unit))
266    {
267        // plain enum without nested structs/tuples
268        return Ok(impl_optionable_self(
269            crate_name,
270            &ty_ident,
271            attr_no_convert.is_some(),
272        ));
273    }
274
275    let k8s_resource_type = k8s_resource_type(attr_k8s_openapi.as_ref(), attr_kube.as_ref())?;
276    let k8s_openapi_attrs = attr_k8s_openapi.is_some().then(|| k8s_type_attr(&data));
277    let attr_copy_identifier = field_attr_copy_hashmap(attr_copy, attr_kube.as_ref());
278    let ty_attr_forwarded = forwarded_attributes(&attrs, &attr_copy_identifier)?;
279
280    let mut derive = attr_derive
281        .into_iter()
282        .flat_map(|el| {
283            el.iter()
284                .map(|el| el.to_token_stream().to_string())
285                .collect::<Vec<_>>()
286        })
287        .collect::<BTreeSet<_>>();
288    if (attr_k8s_openapi.is_some() || attr_kube.is_some())
289        && let Some(k8s_derives) = k8s_derives(&data)
290    {
291        for el in k8s_derives {
292            derive.insert(el);
293        }
294    }
295
296    let vis = vis;
297    // basically split_for_impl, but we move the where clause out instead of just taking a reference
298    let where_clause = take(&mut generics.where_clause);
299    let (impl_generics, ty_generics, _) = generics.split_for_impl();
300    let generics_colon = (!generics.params.is_empty()).then(|| quote! {::});
301    let skip_optionable_if_serde_serialize =
302        (attr_k8s_openapi.is_some() // also sets #[derive(Serialize)]
303            || derive.iter().any(|el| is_serialize(el.as_str())))
304        .then(|| quote!(#[serde(skip_serializing_if = "Option::is_none")]));
305
306    /// Helper to collect the enum/struct specific derived code aspects in a typesafe way
307    struct Derived {
308        /// Either `enum` or `struct`
309        enum_struct: TokenStream,
310        /// The generated fields, including wrapping brackets
311        fields: TokenStream,
312        /// The `where`-clause for the `Optionable`-impl
313        where_clause_optionable: WhereClause,
314        /// The `where`-clause  for the `OptionableConvert` and `OptionedConvert` impl
315        where_clause_optionable_convert: Option<WhereClause>,
316        /// The `OptionableConvert` implementation if not configured to be skipped, including the `impl`-wrapper
317        impl_optionable_convert: Option<TokenStream>,
318    }
319    let Derived {
320        enum_struct,
321        fields,
322        where_clause_optionable,
323        where_clause_optionable_convert,
324        impl_optionable_convert,
325    } = match data {
326        Data::Struct(s) => {
327            let mut struct_parsed = into_field_handling(
328                crate_name.to_owned(),
329                s.fields,
330                settings.input_crate_replacement.as_ref(),
331                attr_option_wrap,
332            )?;
333            k8s_adjust_fields(
334                settings.input_crate_replacement.as_ref(),
335                &mut struct_parsed,
336                attr_k8s_openapi.as_ref(),
337                attr_kube.as_ref(),
338                k8s_resource_type.as_ref(),
339                crate_name,
340            )?;
341            let WhereClauses {
342                optionable: where_clause_optionable,
343                optionable_convert: where_clause_optionable_convert,
344            } = where_clauses(
345                where_clause,
346                &generics.params,
347                crate_name,
348                settings.input_crate_replacement.as_ref(),
349                &derive,
350                attr_no_convert.is_some(),
351                &struct_parsed.fields,
352            )?;
353            let unnamed_struct_semicolon =
354                (struct_parsed.struct_type == StructType::Unnamed).then(|| quote!(;));
355            let optioned_fields = optioned_fields(
356                &struct_parsed,
357                skip_optionable_if_serde_serialize.as_ref(),
358                &attr_copy_identifier,
359            )?;
360
361            let impl_optionable_convert = attr_no_convert.is_none().then(|| {
362                let into_optioned_fields = into_optioned(&struct_parsed, |selector| quote! { self.#selector });
363                let try_from_optioned_fields =
364                    try_from_optioned(&struct_parsed, |selector| quote! { value.#selector });
365                let merge_fields = merge_fields(
366                    &struct_parsed,
367                    |selector| quote! { self.#selector },
368                    |selector| quote! { other.#selector },
369                    true);
370                quote! {
371                    #[automatically_derived]
372                    impl #impl_generics #crate_name::OptionableConvert for #ty_ident #ty_generics #where_clause_optionable_convert{
373                        fn into_optioned(self) -> #ty_ident_opt #ty_generics {
374                            #ty_ident_opt #generics_colon #ty_generics #into_optioned_fields
375                        }
376
377                        fn try_from_optioned(value: #ty_ident_opt #ty_generics) -> Result<Self, #crate_name::Error>{
378                            Ok(Self #try_from_optioned_fields)
379                        }
380
381                        fn merge(&mut self, other: #ty_ident_opt #ty_generics) -> Result<(), #crate_name::Error>{
382                            #merge_fields
383                            Ok(())
384                        }
385                    }
386                }
387            });
388            Derived {
389                enum_struct: quote! {struct},
390                fields: quote! {#optioned_fields #unnamed_struct_semicolon},
391                where_clause_optionable,
392                where_clause_optionable_convert,
393                impl_optionable_convert,
394            }
395        }
396        Data::Enum(e) => {
397            let self_prefix = quote! {self_};
398            let other_prefix = quote! {other_};
399
400            let variants = e
401                .variants
402                .into_iter()
403                .map(|v| {
404                    error_on_helper_attributes(&v.attrs, ERR_MSG_HELPER_ATTR_ENUM_VARIANTS)?;
405                    let mut field_handling = into_field_handling(
406                        crate_name.to_owned(),
407                        v.fields,
408                        settings.input_crate_replacement.as_ref(),
409                        attr_option_wrap,
410                    )?;
411                    k8s_adjust_fields(
412                        settings.input_crate_replacement.as_ref(),
413                        &mut field_handling,
414                        attr_k8s_openapi.as_ref(),
415                        attr_kube.as_ref(),
416                        k8s_resource_type.as_ref(),
417                        crate_name,
418                    )?;
419                    Ok::<_, Error>((
420                        v.ident,
421                        forwarded_attributes(&v.attrs, &attr_copy_identifier)?,
422                        field_handling,
423                    ))
424                })
425                .collect::<Result<Vec<_>, _>>()?;
426            let all_fields = variants
427                .iter()
428                .flat_map(|(_, _, fields)| &fields.fields)
429                .collect::<Vec<_>>();
430            let WhereClauses {
431                optionable: where_clause_optionable,
432                optionable_convert: where_clause_optionable_convert,
433            } = where_clauses(
434                where_clause,
435                &generics.params,
436                crate_name,
437                settings.input_crate_replacement.as_ref(),
438                &derive,
439                attr_no_convert.is_some(),
440                all_fields,
441            )?;
442
443            let optioned_variants = variants
444                .iter()
445                .map(|(variant, forward_attrs, f)| {
446                    let fields = optioned_fields(
447                        f,
448                        skip_optionable_if_serde_serialize.as_ref(),
449                        &attr_copy_identifier,
450                    )?;
451                    Ok::<_, Error>(quote!( #forward_attrs #variant #fields ))
452                })
453                .collect::<Result<Vec<_>, _>>()?;
454
455            let impl_optionable_convert = attr_no_convert.is_none().then(|| {
456                let (into_variants, try_from_variants, merge_variants): (Vec<_>, Vec<_>, Vec<_>) = variants
457                    .iter()
458                    .map(|(variant, _, struct_parsed)| {
459                        let fields_into = into_optioned(struct_parsed, |selector| {
460                            format_ident!("{self_prefix}{selector}").to_token_stream()
461                        });
462                        let fields_try_from = try_from_optioned
463                            (struct_parsed, |selector| {
464                                format_ident!("{other_prefix}{selector}").to_token_stream()
465                            });
466                        let fields_merge = merge_fields(struct_parsed,
467                                                        |selector| format_ident!("{self_prefix}{selector}").to_token_stream(),
468                                                        |selector| format_ident!("{other_prefix}{selector}").to_token_stream(),
469                                                        false);
470                        let self_destructure = destructure(struct_parsed, &self_prefix)?;
471                        let other_destructure = destructure(struct_parsed, &other_prefix)?;
472                        Ok::<_, Error>((
473                            quote!( Self::#variant #self_destructure => #ty_ident_opt::#variant #fields_into ),
474                            quote!( #ty_ident_opt::#variant #other_destructure => Self::#variant #fields_try_from ),
475                            quote!( #ty_ident_opt::#variant #other_destructure => {
476                                if let Self::#variant #self_destructure = self {
477                                    #fields_merge
478                                } else {
479                                    *self = Self::try_from_optioned(#ty_ident_opt::#variant #other_destructure)?;
480                                }
481                            })
482                        ))
483                    })
484                    .collect::<Result<Vec<_>, _>>()?
485                    .into_iter().multiunzip();
486                Ok::<_, Error>(quote! {
487                    #[automatically_derived]
488                    impl #impl_generics #crate_name::OptionableConvert for #ty_ident #ty_generics #where_clause_optionable_convert {
489                        fn into_optioned(self) -> #ty_ident_opt #ty_generics {
490                            match self {
491                                #(#into_variants),*
492                            }
493                        }
494
495                        fn try_from_optioned(other: #ty_ident_opt #ty_generics)->Result<Self,#crate_name::Error>{
496                            Ok(match other{
497                                #(#try_from_variants),*
498                            })
499                        }
500
501                        fn merge(&mut self, other: #ty_ident_opt #ty_generics) -> Result<(), #crate_name::Error>{
502                            match other{
503                                #(#merge_variants),*
504                            }
505                            Ok(())
506                        }
507                    }
508                })
509            }).transpose()?;
510            Derived {
511                enum_struct: quote! {enum},
512                fields: quote! {{#(#optioned_variants),*}},
513                where_clause_optionable,
514                where_clause_optionable_convert,
515                impl_optionable_convert,
516            }
517        }
518        Data::Union(_) => return error("#[derive(Optionable)] not supported for unit structs"),
519    };
520    let impl_optioned_convert = attr_no_convert.is_none().then(|| {
521        quote! {
522            #[automatically_derived]
523            impl #impl_generics #crate_name::OptionedConvert<#ty_ident #ty_generics> for #ty_ident_opt #ty_generics #where_clause_optionable_convert {
524                fn from_optionable(value: #ty_ident #ty_generics) -> Self {
525                    #crate_name::OptionableConvert::into_optioned(value)
526                }
527                fn try_into_optionable(self) -> Result<#ty_ident #ty_generics, #crate_name::Error> {
528                    #crate_name::OptionableConvert::try_from_optioned(self)
529                }
530                fn merge_into(self, other: &mut #ty_ident #ty_generics) -> Result<(), #crate_name::Error> {
531                    #crate_name::OptionableConvert::merge(other, self)
532                }
533            }
534        }
535    });
536
537    let derive = derive
538        .into_iter()
539        .map(|derive| Path::from_string(&derive))
540        .collect::<Result<Vec<_>, _>>()?;
541    let derive = (!derive.is_empty()).then(|| quote! {#[derive(#(#derive),*)]});
542
543    let k8s_openapi_impl_resource = attr_k8s_openapi
544        .as_ref()
545        .is_some_and(|attr| attr.resource.is_some())
546        .then(|| {
547            k8s_openapi_impl_resource(
548                settings.input_crate_replacement.as_ref(),
549                &ty_ident,
550                &ty_ident_opt,
551                &impl_generics,
552                &ty_generics,
553                &where_clause_optionable,
554            )
555        });
556    let impl_k8s_metadata = attr_k8s_openapi
557        .as_ref()
558        .is_some_and(|attr| attr.metadata.is_some())
559        .then(|| {
560            k8s_openapi_impl_metadata(
561                settings.input_crate_replacement.as_ref(),
562                &ty_ident,
563                &ty_ident_opt,
564                &impl_generics,
565                &ty_generics,
566                &where_clause_optionable,
567            )
568        });
569    let kube_derive_resource = attr_kube
570        .is_some_and(|attr| attr.resource.is_some())
571        .then(|| {
572            quote! {
573                #[derive(kube::Resource)]
574                #[resource(inherit = #ty_ident )]
575            }
576        });
577    let k8s_roundtrip_test = (attr_k8s_openapi.is_some_and(|attr|attr.resource.is_some())
578        && ty_generics.to_token_stream().is_empty()
579        // causes stackoverflows during the roundtrip tests, the stackoverflow already happens when trying to generate a `fake CRD`, so doesn't originate from this crate
580        // (we rely on a forked version of k8s-openapi where we just added derives for `fake::Dummy`, but the CRD includes a `JSONSchemaProps` subfield which includes a lot
581        // of other subfields involving `JSONSchemaProps`. Hence, `fake` easily generates a way to complicated and depply nested random structure).
582        && ty_ident_opt!="CustomResourceDefinitionAc"
583        // the cases below cause false positive errors due to flattening of effectively nil substructs in the  optioned type
584        && ty_ident_opt!="StorageVersionAc"
585        && ty_ident_opt!="DeviceClassAc"
586        && ty_ident_opt!="ResourceClaimAc"
587        && ty_ident_opt!="ResourceClaimTemplateAc")
588        .then(|| {
589            let fn_name = format_ident!(
590                "roundtrip_{}",
591                ty_ident_opt.to_token_stream().to_string().to_lowercase()
592            );
593            Ok::<_, Error>(quote! {
594                #[cfg(test_k8s_openapi_roundtrip)]
595                #[test]
596                fn #fn_name() {
597                   crate::testutil::roundtrip_test::<#ty_ident>();
598                }
599            })
600        })
601        .transpose()?;
602    Ok(quote! {
603                #derive
604                #kube_derive_resource
605                #ty_attr_forwarded
606                #k8s_openapi_attrs
607                #vis #enum_struct #ty_ident_opt #impl_generics #where_clause_optionable #fields
608
609                #[automatically_derived]
610                impl #impl_generics #crate_name::Optionable for #ty_ident #ty_generics #where_clause_optionable {
611                    type Optioned = #ty_ident_opt #ty_generics;
612                }
613
614                #[automatically_derived]
615                impl #impl_generics #crate_name::Optionable for #ty_ident_opt #ty_generics #where_clause_optionable {
616                    type Optioned = #ty_ident_opt #ty_generics;
617                }
618
619                #impl_optionable_convert
620                #impl_optioned_convert
621
622                #k8s_openapi_impl_resource
623                #impl_k8s_metadata
624
625                #k8s_roundtrip_test
626    })
627}
628
629/// Returns the `Optionable` and `OptionableConvert` implementation for self-resolving types
630fn impl_optionable_self(crate_name: &Path, ty_ident: &Path, no_convert: bool) -> TokenStream {
631    let convert_impl = (!no_convert).then(|| {
632        quote! {
633            #[automatically_derived]
634            impl #crate_name::OptionableConvert for #ty_ident{
635                fn into_optioned(self) -> #ty_ident {
636                    self
637                }
638
639                fn try_from_optioned(value: Self::Optioned) -> Result<Self, #crate_name::Error> {
640                    Ok(value)
641                }
642
643                fn merge(&mut self, other: Self::Optioned) -> Result<(), #crate_name::Error> {
644                    *self = other;
645                    Ok(())
646                }
647            }
648        }
649    });
650    quote! {
651        #[automatically_derived]
652        impl #crate_name::Optionable for #ty_ident{
653            type Optioned = Self;
654        }
655
656        #convert_impl
657    }
658}
659
660/// Returns a tokenstream for the optioned fields and potential convert implementation of the optioned object (struct/enum variants).
661/// The returned tokenstream will be of the form `{...}` for named fields and `(...)` for unnamed fields.
662/// Does not include any leading `struct/enum` keywords or any trailing `;`.
663fn optioned_fields(
664    fields: &StructParsed,
665    serde_attributes: Option<&TokenStream>,
666    field_attr_forwards: &HashMap<Path, HashSet<Path>>,
667) -> Result<TokenStream, Error> {
668    let fields_token = fields.fields.iter().map(
669        |FieldParsed {
670             field: Field { attrs, vis, ident, ty, .. },
671             handling,
672         }| {
673            let forwarded_attrs = forwarded_attributes(attrs, field_attr_forwards)?;
674            let optioned_ty = optioned_ty(&fields.crate_name, ty);
675            let colon = ident.as_ref().map(|_| quote! {:});
676            Ok::<_, Error>(match handling {
677                FieldHandling::Required | FieldHandling::OptionedOnly => quote! {#forwarded_attrs #vis #ident #colon #ty},
678                FieldHandling::ManualOptioned(ty_opt) => quote! {#forwarded_attrs #vis #ident #colon Option<#ty_opt>},
679                FieldHandling::IsOption => quote! {#forwarded_attrs #serde_attributes #vis #ident #colon #optioned_ty},
680                FieldHandling::Other => quote! {#forwarded_attrs #serde_attributes #vis #ident #colon Option<#optioned_ty>},
681            })
682        },
683    ).collect::<Result<Vec<_>, _>>()?;
684    Ok(struct_wrapper(fields_token, &fields.struct_type))
685}
686
687/// Returns the field mapping implementation for `into_optioned`.
688/// The returned tokenstream will be of the form `{...}` for named fields and `(...)` for unnamed fields.
689/// Does not include any leading `struct/enum` keywords or any trailing `;`.
690fn into_optioned(
691    struct_parsed: &StructParsed,
692    self_selector_fn: impl Fn(&TokenStream) -> TokenStream,
693) -> TokenStream {
694    let fields_token = struct_parsed.fields.iter().enumerate().map(|(i, FieldParsed { field: Field { ident, ty, .. }, handling })| {
695        let colon = ident.as_ref().map(|_| quote! {:});
696        let selector = ident.as_ref().map_or_else(|| {
697            let i = Literal::usize_unsuffixed(i);
698            quote! {#i}
699        }, ToTokens::to_token_stream);
700        let self_selector = self_selector_fn(&selector);
701        let crate_name = &struct_parsed.crate_name;
702        match (handling, is_self_resolving_optioned(ty)) {
703            (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => quote! {#ident #colon #self_selector},
704            (FieldHandling::ManualOptioned(_), _) => quote! {#ident #colon Some(#crate_name::OptionedConvert::from_optionable(#self_selector))},
705            (FieldHandling::IsOption, false) => quote! {#ident #colon #crate_name::OptionableConvert::into_optioned(#self_selector)},
706            (FieldHandling::Other, true) => quote! {#ident #colon Some(#self_selector)},
707            (FieldHandling::Other, false) => quote! {#ident #colon Some(#crate_name::OptionableConvert::into_optioned(#self_selector))},
708            (FieldHandling::OptionedOnly, _) => quote! {#ident #colon Default::default()},
709        }
710    });
711    struct_wrapper(fields_token, &struct_parsed.struct_type)
712}
713
714/// Returns the field-mappings implementation for `try_from_optioned`.
715/// The returned tokenstream will be of the form `{...}` for named fields and `(...)` for unnamed fields.
716/// Does not include any leading `struct/enum` keywords or any trailing `;`.
717fn try_from_optioned(
718    struct_parsed: &StructParsed,
719    value_selector_fn: impl Fn(&TokenStream) -> TokenStream,
720) -> TokenStream {
721    let fields_token = struct_parsed.fields.iter().enumerate().filter_map(|(i, FieldParsed { field: Field { ident, ty, .. }, handling })| {
722        let colon = ident.as_ref().map(|_| quote! {:});
723        let selector = ident.as_ref().map_or_else(|| {
724            let i = Literal::usize_unsuffixed(i);
725            quote! {#i}
726        }, ToTokens::to_token_stream);
727        let value_selector = value_selector_fn(&selector);
728        let crate_name = &struct_parsed.crate_name;
729        match (handling, is_self_resolving_optioned(ty)) {
730            (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => Some(quote! {#ident #colon value.#selector}),
731            (FieldHandling::ManualOptioned(_), _) => {
732                let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
733                Some(quote! {
734                    #ident #colon #crate_name::OptionedConvert::try_into_optionable(#value_selector.ok_or(#crate_name::Error{ missing_field: #selector_quoted })?
735                    )?
736                })
737            }
738            (FieldHandling::IsOption, false) => Some(quote! {
739                #ident #colon #crate_name::OptionableConvert::try_from_optioned(
740                    #value_selector
741                )?
742            }),
743            (FieldHandling::Other, true) => {
744                let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
745                Some(quote! {
746                    #ident #colon #value_selector.ok_or(#crate_name::Error{ missing_field: #selector_quoted })?
747                })
748            }
749            (FieldHandling::Other, false) => {
750                let selector_quoted = LitStr::new(&selector.to_string(), ident.span());
751                Some(quote! {
752                    #ident #colon #crate_name::OptionableConvert::try_from_optioned(#value_selector.ok_or(#crate_name::Error{ missing_field: #selector_quoted })?
753                    )?
754                })
755            }
756            (FieldHandling::OptionedOnly, _) => None,
757        }
758    });
759
760    struct_wrapper(fields_token, &struct_parsed.struct_type)
761}
762
763/// Returns the field-mappings implementation for `try_from_optioned`.
764/// The returned tokenstream will be of the form `{...}` for named fields and `(...)` for unnamed fields.
765/// Does not include any leading `struct/enum` keywords or any trailing `;`.
766///
767/// `merge_self_mut` should be true when the `self_selector` merge argument should be modified with a `& mut` on recursive calls.
768fn merge_fields(
769    struct_parsed: &StructParsed,
770    self_selector_fn: impl Fn(&TokenStream) -> TokenStream,
771    other_selector_fn: impl Fn(&TokenStream) -> TokenStream,
772    merge_self_mut: bool,
773) -> TokenStream {
774    let fields_token = struct_parsed.fields.iter().enumerate().filter_map(
775        |(
776             i,
777             FieldParsed {
778                 field: Field { ident, ty, .. },
779                 handling,
780             },
781         )| {
782            let selector = ident.as_ref().map_or_else(
783                || {
784                    let i = Literal::usize_unsuffixed(i);
785                    quote! {#i}
786                },
787                ToTokens::to_token_stream,
788            );
789            let self_merge_mut_modifier = merge_self_mut.then(|| quote! {&mut});
790            let deref_modifier = (!merge_self_mut).then(|| quote! {*});
791            let self_selector = self_selector_fn(&selector);
792            let other_selector = other_selector_fn(&selector);
793            let crate_name = &struct_parsed.crate_name;
794            match (handling, is_self_resolving_optioned(ty)) {
795                (FieldHandling::Required, _) | (FieldHandling::IsOption, true) => Some(quote! {#deref_modifier #self_selector = #other_selector;}),
796                (FieldHandling::ManualOptioned(_), _) =>  Some(quote! {
797                    if let Some(other_value)=#other_selector{
798                        #crate_name::OptionedConvert::merge_into(other_value, #self_merge_mut_modifier #self_selector)?;
799                    }
800                }),
801                (FieldHandling::IsOption, false) =>  Some(quote! {
802                    #crate_name::OptionableConvert::merge(#self_merge_mut_modifier #self_selector, #other_selector)?;
803                }),
804                (FieldHandling::Other, true) =>  Some(quote! {
805                    if let Some(other_value)=#other_selector{
806                        #deref_modifier #self_selector = other_value;
807                    }
808                }),
809                (FieldHandling::Other, false) =>  Some(quote! {
810                    if let Some(other_value)=#other_selector{
811                        #crate_name::OptionableConvert::merge(#self_merge_mut_modifier #self_selector, other_value)?;
812                    }
813                }),
814                (FieldHandling::OptionedOnly, _) =>None,
815            }
816        },
817    );
818
819    quote! {
820        #(#fields_token)*
821    }
822}
823/// Tries to resolve the optioned type analogous to what we do in the main crate.
824/// Due to limitations to macro resolving (no order guaranteed) we have to have an explicit
825/// list of well-known types and their optioned types.
826/// For now limited to self-resolving (mostly primitive) types
827fn optioned_ty(crate_name: &Path, ty: &Type) -> TokenStream {
828    if is_self_resolving_optioned(ty) {
829        ty.to_token_stream()
830    } else {
831        quote! { <#ty as #crate_name::Optionable>::Optioned }
832    }
833}
834
835const SELF_RESOLVING_TYPES: [&str; 18] = [
836    // Rust primitives don't have inner structure, https://doc.rust-lang.org/rust-by-example/primitives.html
837    "i8", "i16", "i32", "i64", "i128", "isize", "u8", "u16", "u32", "u64", "u128", "usize", "f32",
838    "f64", "char", "bool", // Other types without inner structure
839    "String", "OsString",
840];
841
842/// Checks when it is well known that the type resolves to itself as its `Optioned`.
843/// Limited to self-resolving (mostly primitive) types.
844fn is_self_resolving_optioned(ty: &Type) -> bool {
845    if let Type::Path(TypePath { qself, path }) = &ty
846        && qself.is_none()
847        && SELF_RESOLVING_TYPES.contains(&&*path.to_token_stream().to_string())
848    {
849        true
850    } else {
851        false
852    }
853}
854
855/// Extracts the `HELPER_ATTR_IDENT` attributes, unwraps them and returns them
856/// as `TokenStream` that can be used as respective attribute.
857fn forwarded_attributes(
858    attrs: &[Attribute],
859    attr_to_copy: &HashMap<Path, HashSet<Path>>,
860) -> Result<Option<TokenStream>, Error> {
861    let forward_attrs = attrs
862        .iter()
863        .map(|attr| {
864            if attr.path().is_ident(HELPER_ATTR_IDENT) {
865                return match &attr.meta {
866                    Meta::List(MetaList { tokens, .. }) => Ok(Some(quote!(#[#tokens]))),
867                    _ => error("Only lists like `#[optionable_attr(Serialize,Deserialize)]` are supported for `optionable_attr`"),
868                };
869            }
870            let keys_to_copy = attr_to_copy.get(attr.path());
871            if let Some(keys_to_copy) = keys_to_copy {
872                // no key restrictions
873                if keys_to_copy.is_empty() {
874                    if attr.path().is_ident("derive") && let Meta::List(meta_list) = &attr.meta {
875                        let derives = Punctuated::<Path, Token![,]>::parse_terminated
876                            .parse2(meta_list.tokens.clone())?.into_iter().filter(|el| el.to_token_stream().to_string() != "Optionable" && el.to_token_stream().to_string() != "optionable::Optionable");
877                        return Ok(Some(quote! {#[derive(#(#derives,)*)]}));
878                    }
879                    Ok(Some(attr.to_token_stream()))
880                } else {
881                    match &attr.meta {
882                        Meta::Path(_) => Ok(None),
883                        Meta::NameValue(meta_name_value) => Ok(keys_to_copy.contains(&meta_name_value.path).then(|| attr.to_token_stream())),
884                        Meta::List(meta_list) => {
885                            // we support one level of nesting for a Meta::List(Meta::NameValue(..)) setup like it's used by #[serde(rename=...)]
886                            let inner_metas: Vec<TokenStream> = Punctuated::<Meta, Token![,]>::parse_terminated
887                                .parse2(meta_list.tokens.clone())?.into_iter().filter_map(|meta| {
888                                if let Meta::NameValue(meta_name_value) = meta {
889                                    keys_to_copy.contains(&meta_name_value.path).then(|| Ok::<_, Error>(meta_name_value.to_token_stream()))
890                                } else {
891                                    None
892                                }
893                            }).collect::<Result<_, _>>()?;
894                            if inner_metas.is_empty() {
895                                Ok(None)
896                            } else {
897                                let attr = Attribute {
898                                    meta: MetaList {
899                                        path: meta_list.path.clone(),
900                                        delimiter: meta_list.delimiter.clone(),
901                                        tokens: inner_metas.into_iter().collect(),
902                                    }.into(),
903                                    ..*attr
904                                };
905                                Ok(Some(attr.to_token_stream()))
906                            }
907                        }
908                    }
909                }
910            } else {
911                Ok(None)
912            }
913        })
914        .collect::<Result<Vec<_>, _>>()?
915        .into_iter()
916        .flatten()
917        .collect::<TokenStream>();
918    Ok((!forward_attrs.is_empty()).then_some(forward_attrs))
919}
920
921#[cfg(test)]
922mod tests {
923    use crate::{derive_optionable, CodegenSettings};
924    use darling::FromMeta;
925    use proc_macro2::TokenStream;
926    use quote::quote;
927    use syn::{parse_quote, Path};
928
929    struct TestCase {
930        input: TokenStream,
931        output: TokenStream,
932    }
933
934    #[test]
935    #[allow(clippy::too_many_lines)]
936    fn test_optionable() {
937        let tcs = vec![
938            // named struct fields
939            TestCase {
940                input: quote! {
941                    #[derive(Optionable)]
942                    struct DeriveExample {
943                        name: String,
944                        pub surname: String,
945                    }
946                },
947                output: quote! {
948                    struct DeriveExampleOpt {
949                        name: Option<String>,
950                        pub surname: Option<String>
951                    }
952
953                    #[automatically_derived]
954                    impl ::optionable::Optionable for DeriveExample {
955                        type Optioned = DeriveExampleOpt;
956                    }
957
958                    #[automatically_derived]
959                    impl ::optionable::Optionable for DeriveExampleOpt {
960                        type Optioned = DeriveExampleOpt;
961                    }
962
963                    #[automatically_derived]
964                    impl ::optionable::OptionableConvert for DeriveExample {
965                        fn into_optioned (self) -> DeriveExampleOpt {
966                            DeriveExampleOpt  {
967                                name: Some(self.name),
968                                surname:Some(self.surname)
969                            }
970                        }
971
972                        fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
973                            Ok(Self{
974                                name: value.name.ok_or(::optionable::Error { missing_field: "name" })?,
975                                surname: value.surname.ok_or(::optionable::Error { missing_field: "surname" })?
976                            })
977                        }
978
979                        fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
980                            if let Some(other_value) = other.name {
981                                self.name = other_value;
982                            }
983                            if let Some(other_value) = other.surname {
984                                self.surname = other_value;
985                            }
986                            Ok(())
987                        }
988                    }
989
990                    #[automatically_derived]
991                    impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
992                        fn from_optionable(value: DeriveExample) -> Self {
993                            ::optionable::OptionableConvert::into_optioned(value)
994                        }
995
996                        fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
997                            ::optionable::OptionableConvert::try_from_optioned(self)
998                        }
999
1000                        fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1001                            ::optionable::OptionableConvert::merge(other, self)
1002                        }
1003                    }
1004                },
1005            },
1006            // named struct fields, no convert impl
1007            TestCase {
1008                input: quote! {
1009                    #[derive(Optionable)]
1010                    #[optionable(no_convert)]
1011                    struct DeriveExample {
1012                        name: String,
1013                        pub surname: String,
1014                    }
1015                },
1016                output: quote! {
1017                    struct DeriveExampleOpt {
1018                        name: Option<String>,
1019                        pub surname: Option<String>
1020                    }
1021
1022                    #[automatically_derived]
1023                    impl ::optionable::Optionable for DeriveExample {
1024                        type Optioned = DeriveExampleOpt;
1025                    }
1026
1027                    #[automatically_derived]
1028                    impl ::optionable::Optionable for DeriveExampleOpt {
1029                        type Optioned = DeriveExampleOpt;
1030                    }
1031                },
1032            },
1033            // named struct fields with required fields
1034            TestCase {
1035                input: quote! {
1036                    #[derive(Optionable)]
1037                    struct DeriveExample {
1038                        name: String,
1039                        #[optionable(required)]
1040                        pub surname: String,
1041                        #[optionable(optioned_type=MyInt)]
1042                        pub id: i32,
1043                    }
1044                },
1045                output: quote! {
1046                    struct DeriveExampleOpt {
1047                        name: Option<String>,
1048                        pub surname: String,
1049                        pub id: Option<MyInt>
1050                    }
1051
1052                    #[automatically_derived]
1053                    impl ::optionable::Optionable for DeriveExample {
1054                        type Optioned = DeriveExampleOpt;
1055                    }
1056
1057                    #[automatically_derived]
1058                    impl ::optionable::Optionable for DeriveExampleOpt {
1059                        type Optioned = DeriveExampleOpt;
1060                    }
1061
1062                    #[automatically_derived]
1063                    impl ::optionable::OptionableConvert for DeriveExample {
1064                        fn into_optioned (self) -> DeriveExampleOpt {
1065                            DeriveExampleOpt  {
1066                                name: Some(self.name),
1067                                surname: self.surname,
1068                                id: Some (::optionable::OptionedConvert::from_optionable(self.id))
1069                            }
1070                        }
1071
1072                        fn try_from_optioned(value:DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
1073                            Ok (Self {
1074                                name: value.name.ok_or(::optionable::Error { missing_field: "name" })?,
1075                                surname: value.surname,
1076                                id: ::optionable::OptionedConvert::try_into_optionable(value.id.ok_or(::optionable::Error{ missing_field: "id" })?)?
1077                            })
1078                        }
1079
1080                        fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
1081                            if let Some(other_value) = other.name {
1082                                self.name = other_value;
1083                            }
1084                            self.surname = other.surname;
1085                            if let Some (other_value) = other.id {
1086                                ::optionable::OptionedConvert::merge_into(other_value, &mut self.id)?;
1087                            }
1088                            Ok (())
1089                        }
1090                    }
1091
1092
1093                    #[automatically_derived]
1094                    impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
1095                        fn from_optionable(value: DeriveExample) -> Self {
1096                            ::optionable::OptionableConvert::into_optioned(value)
1097                        }
1098
1099                        fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1100                            ::optionable::OptionableConvert::try_from_optioned(self)
1101                        }
1102
1103                        fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1104                            ::optionable::OptionableConvert::merge(other, self)
1105                        }
1106                    }
1107                },
1108            },
1109            // named struct fields with forwarded derives and Serialize annotations
1110            TestCase {
1111                input: quote! {
1112                    #[derive(Optionable)]
1113                    #[optionable(derive(Deserialize,Serialize,Default),suffix="Ac")]
1114                    #[optionable(attr_copy(attr=serde,key=rename))]
1115                    #[optionable_attr(serde(rename_all_fields = "camelCase", deny_unknown_fields))]
1116                    #[optionable_attr(serde(default))]
1117                    struct DeriveExample {
1118                        #[optionable_attr(serde(rename = "firstName"))]
1119                        name: String,
1120                        #[serde(rename="middle__name")]
1121                        middle_name: Option<String>,
1122                        surname: String,
1123                    }
1124                },
1125                output: quote! {
1126                    #[derive(Default, Deserialize, Serialize)]
1127                    #[serde(rename_all_fields = "camelCase", deny_unknown_fields)]
1128                    #[serde(default)]
1129                    struct DeriveExampleAc {
1130                        #[serde(rename = "firstName")]
1131                        #[serde(skip_serializing_if = "Option::is_none")]
1132                        name: Option<String>,
1133                        #[serde(rename = "middle__name")]
1134                        #[serde(skip_serializing_if = "Option::is_none")]
1135                        middle_name: <Option<String> as ::optionable::Optionable>::Optioned,
1136                        #[serde(skip_serializing_if = "Option::is_none")]
1137                        surname: Option<String>
1138                    }
1139
1140                    #[automatically_derived]
1141                    impl ::optionable::Optionable for DeriveExample {
1142                        type Optioned = DeriveExampleAc;
1143                    }
1144
1145                    #[automatically_derived]
1146                    impl ::optionable::Optionable for DeriveExampleAc {
1147                        type Optioned = DeriveExampleAc;
1148                    }
1149
1150                    #[automatically_derived]
1151                    impl ::optionable::OptionableConvert for DeriveExample {
1152                        fn into_optioned (self) -> DeriveExampleAc {
1153                            DeriveExampleAc  {
1154                                name: Some(self.name),
1155                                middle_name: ::optionable::OptionableConvert::into_optioned(self.middle_name),
1156                                surname: Some(self.surname)
1157                            }
1158                        }
1159
1160                        fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::Error> {
1161                            Ok(Self{
1162                                name: value.name.ok_or(::optionable::Error { missing_field: "name"})?,
1163                                middle_name: ::optionable::OptionableConvert::try_from_optioned(value.middle_name)?,
1164                                surname: value.surname.ok_or(::optionable::Error { missing_field: "surname"})?
1165                            })
1166                        }
1167
1168                        fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::Error> {
1169                            if let Some(other_value) = other.name {
1170                                self.name =  other_value;
1171                            }
1172                            ::optionable::OptionableConvert::merge(&mut self.middle_name, other.middle_name)?;
1173                            if let Some(other_value) = other.surname {
1174                                self.surname =  other_value;
1175                            }
1176                            Ok(())
1177                        }
1178                    }
1179
1180
1181                    #[automatically_derived]
1182                    impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleAc {
1183                        fn from_optionable(value: DeriveExample) -> Self {
1184                            ::optionable::OptionableConvert::into_optioned(value)
1185                        }
1186
1187                        fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1188                            ::optionable::OptionableConvert::try_from_optioned(self)
1189                        }
1190
1191                        fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1192                            ::optionable::OptionableConvert::merge(other, self)
1193                        }
1194                    }
1195                },
1196            },
1197            // named struct fields with forwarded derives and Serialize annotations
1198            TestCase {
1199                input: quote! {
1200                    #[derive(Optionable)]
1201                    #[optionable(derive(Deserialize,Serialize,Default),suffix="Ac")]
1202                    #[optionable(attr_copy(attr=serde,key=rename))]
1203                    #[optionable(option_wrap)]
1204                    #[optionable_attr(serde(rename_all_fields = "camelCase", deny_unknown_fields))]
1205                    #[optionable_attr(serde(default))]
1206                    struct DeriveExample {
1207                        #[optionable_attr(serde(rename = "firstName"))]
1208                        name: String,
1209                        #[serde(rename="middle__name")]
1210                        middle_name: Option<String>,
1211                        surname: String,
1212                    }
1213                },
1214                output: quote! {
1215                    #[derive(Default, Deserialize, Serialize)]
1216                    #[serde(rename_all_fields = "camelCase", deny_unknown_fields)]
1217                    #[serde(default)]
1218                    struct DeriveExampleAc {
1219                        #[serde(rename = "firstName")]
1220                        #[serde(skip_serializing_if = "Option::is_none")]
1221                        name: Option<String>,
1222                        #[serde(rename = "middle__name")]
1223                        #[serde(skip_serializing_if = "Option::is_none")]
1224                        middle_name: Option< <Option<String> as ::optionable::Optionable>::Optioned>,
1225                        #[serde(skip_serializing_if = "Option::is_none")]
1226                        surname: Option<String>
1227                    }
1228
1229                    #[automatically_derived]
1230                    impl ::optionable::Optionable for DeriveExample {
1231                        type Optioned = DeriveExampleAc;
1232                    }
1233
1234                    #[automatically_derived]
1235                    impl ::optionable::Optionable for DeriveExampleAc {
1236                        type Optioned = DeriveExampleAc;
1237                    }
1238
1239                    #[automatically_derived]
1240                    impl ::optionable::OptionableConvert for DeriveExample {
1241                        fn into_optioned (self) -> DeriveExampleAc {
1242                            DeriveExampleAc  {
1243                                name: Some(self.name),
1244                                middle_name: Some(::optionable::OptionableConvert::into_optioned(self.middle_name)),
1245                                surname: Some(self.surname)
1246                            }
1247                        }
1248
1249                        fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::Error> {
1250                            Ok(Self{
1251                                name: value.name.ok_or(::optionable::Error { missing_field: "name"})?,
1252                                middle_name: ::optionable::OptionableConvert::try_from_optioned(value.middle_name.ok_or(::optionable::Error{ missing_field : "middle_name" })?)?,
1253                                surname: value.surname.ok_or(::optionable::Error { missing_field: "surname"})?
1254                            })
1255                        }
1256
1257                        fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::Error> {
1258                            if let Some(other_value) = other.name {
1259                                self.name =  other_value;
1260                            }
1261                            if let Some(other_value) = other.middle_name {
1262                                ::optionable::OptionableConvert::merge(&mut self.middle_name, other_value)?;
1263                            }
1264                            if let Some(other_value) = other.surname {
1265                                self.surname =  other_value;
1266                            }
1267                            Ok(())
1268                        }
1269                    }
1270
1271
1272                    #[automatically_derived]
1273                    impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleAc {
1274                        fn from_optionable(value: DeriveExample) -> Self {
1275                            ::optionable::OptionableConvert::into_optioned(value)
1276                        }
1277
1278                        fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1279                            ::optionable::OptionableConvert::try_from_optioned(self)
1280                        }
1281
1282                        fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1283                            ::optionable::OptionableConvert::merge(other, self)
1284                        }
1285                    }
1286                },
1287            },
1288            // named struct fields with forwarded derives and Serialize annotations (full path variant)
1289            TestCase {
1290                input: quote! {
1291                    #[derive(Optionable)]
1292                    #[optionable(derive(serde::Deserialize,serde::Serialize),suffix="Ac")]
1293                    struct DeriveExample {
1294                        name: String,
1295                        surname: String,
1296                    }
1297                },
1298                output: quote! {
1299                    #[derive(serde::Deserialize, serde::Serialize)]
1300                    struct DeriveExampleAc {
1301                        #[serde(skip_serializing_if = "Option::is_none")]
1302                        name: Option<String>,
1303                        #[serde(skip_serializing_if = "Option::is_none")]
1304                        surname: Option<String>
1305                    }
1306
1307                    #[automatically_derived]
1308                    impl ::optionable::Optionable for DeriveExample {
1309                        type Optioned = DeriveExampleAc;
1310                    }
1311
1312                    #[automatically_derived]
1313                    impl ::optionable::Optionable for DeriveExampleAc {
1314                        type Optioned = DeriveExampleAc;
1315                    }
1316
1317                    #[automatically_derived]
1318                    impl ::optionable::OptionableConvert for DeriveExample {
1319                        fn into_optioned (self) -> DeriveExampleAc {
1320                            DeriveExampleAc {
1321                                name: Some(self.name),
1322                                surname: Some(self.surname)
1323                            }
1324                        }
1325
1326                        fn try_from_optioned(value: DeriveExampleAc ) -> Result <Self, ::optionable::Error> {
1327                             Ok(Self{
1328                                name: value.name.ok_or(::optionable::Error{ missing_field: "name"})?,
1329                                surname: value.surname.ok_or(::optionable::Error{ missing_field: "surname"})?
1330                            })
1331                        }
1332
1333                        fn merge(&mut self, other: DeriveExampleAc ) -> Result<(), ::optionable::Error> {
1334                            if let Some(other_value) = other.name {
1335                                self.name = other_value;
1336                            }
1337                            if let Some(other_value) = other.surname {
1338                                self.surname = other_value;
1339                            }
1340                            Ok(())
1341                        }
1342                    }
1343
1344                    #[automatically_derived]
1345                    impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleAc {
1346                        fn from_optionable(value: DeriveExample) -> Self {
1347                            ::optionable::OptionableConvert::into_optioned(value)
1348                        }
1349
1350                        fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1351                            ::optionable::OptionableConvert::try_from_optioned(self)
1352                        }
1353
1354                        fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1355                            ::optionable::OptionableConvert::merge(other, self)
1356                        }
1357                    }
1358                },
1359            },
1360            // unnamed struct fields
1361            TestCase {
1362                input: quote! {
1363                    #[derive(Optionable)]
1364                    struct DeriveExample(pub String, i32);
1365                },
1366                output: quote! {
1367                    struct DeriveExampleOpt(
1368                        pub Option<String>,
1369                        Option<i32>
1370                    );
1371
1372                    #[automatically_derived]
1373                    impl ::optionable::Optionable for DeriveExample {
1374                        type Optioned = DeriveExampleOpt;
1375                    }
1376
1377                    #[automatically_derived]
1378                    impl ::optionable::Optionable for DeriveExampleOpt {
1379                        type Optioned = DeriveExampleOpt;
1380                    }
1381
1382                    #[automatically_derived]
1383                    impl ::optionable::OptionableConvert for DeriveExample {
1384                        fn into_optioned (self) -> DeriveExampleOpt {
1385                            DeriveExampleOpt (
1386                                Some(self.0),
1387                                Some(self.1)
1388                            )
1389                        }
1390
1391                         fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
1392                            Ok(Self(
1393                                value.0.ok_or(::optionable::Error { missing_field:"0" })?,
1394                                value.1.ok_or(::optionable::Error { missing_field: "1" })?
1395                            ))
1396                        }
1397
1398                        fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
1399                            if let Some(other_value) = other.0 {
1400                                self.0 = other_value;
1401                            }
1402                            if let Some (other_value) = other.1 {
1403                                self.1 = other_value;
1404                            }
1405                            Ok (())
1406                        }
1407                    }
1408
1409
1410                    #[automatically_derived]
1411                    impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
1412                        fn from_optionable(value: DeriveExample) -> Self {
1413                            ::optionable::OptionableConvert::into_optioned(value)
1414                        }
1415
1416                        fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1417                            ::optionable::OptionableConvert::try_from_optioned(self)
1418                        }
1419
1420                        fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1421                            ::optionable::OptionableConvert::merge(other, self)
1422                        }
1423                    }
1424                },
1425            },
1426            // unnamed struct fields with required
1427            TestCase {
1428                input: quote! {
1429                    #[derive(Optionable)]
1430                    struct DeriveExample(pub String, #[optionable(required)] i32);
1431                },
1432                output: quote! {
1433                    struct DeriveExampleOpt(
1434                        pub Option<String>,
1435                        i32
1436                    );
1437
1438                    #[automatically_derived]
1439                    impl ::optionable::Optionable for DeriveExample {
1440                        type Optioned = DeriveExampleOpt;
1441                    }
1442
1443                    #[automatically_derived]
1444                    impl ::optionable::Optionable for DeriveExampleOpt {
1445                        type Optioned = DeriveExampleOpt;
1446                    }
1447
1448                    # [automatically_derived]
1449                    impl ::optionable::OptionableConvert for DeriveExample {
1450                        fn into_optioned (self) -> DeriveExampleOpt {
1451                            DeriveExampleOpt (
1452                                Some(self.0),
1453                                self.1
1454                            )
1455                        }
1456
1457                         fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, ::optionable::Error> {
1458                            Ok(Self(
1459                                value.0.ok_or(::optionable::Error { missing_field: "0" })?,
1460                                value.1))
1461                        }
1462
1463                        fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), ::optionable::Error> {
1464                            if let Some(other_value) = other.0 {
1465                                self.0 = other_value;
1466                            }
1467                            self.1 = other.1;
1468                            Ok (())
1469                        }
1470                    }
1471
1472
1473                    #[automatically_derived]
1474                    impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
1475                        fn from_optionable(value: DeriveExample) -> Self {
1476                            ::optionable::OptionableConvert::into_optioned(value)
1477                        }
1478
1479                        fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1480                            ::optionable::OptionableConvert::try_from_optioned(self)
1481                        }
1482
1483                        fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1484                            ::optionable::OptionableConvert::merge(other, self)
1485                        }
1486                    }
1487                },
1488            },
1489            // named struct fields with generics
1490            TestCase {
1491                input: quote! {
1492                    #[derive(Optionable)]
1493                    #[optionable(derive(Serialize, Deserialize))]
1494                    struct DeriveExample<'a, T, T2: Serialize, T3> {
1495                        output: T,
1496                        input: Cow<'a, T2>,
1497                        #[optionable(required)]
1498                        extra: T3,
1499                    }
1500                },
1501                output: quote! {
1502                    #[derive (Deserialize, Serialize)]
1503                    struct DeriveExampleOpt<'a, T, T2: Serialize, T3>
1504                        where T: ::optionable::Optionable,
1505                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1506                              Cow<'a ,T2>: ::optionable::Optionable,
1507                              <Cow<'a,T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1508                    {
1509                        #[serde(skip_serializing_if="Option::is_none")]
1510                        output: Option< <T as ::optionable::Optionable>::Optioned>,
1511                        #[serde(skip_serializing_if="Option::is_none")]
1512                        input: Option< <Cow<'a, T2> as ::optionable::Optionable>::Optioned>,
1513                        extra: T3
1514                    }
1515
1516                    #[automatically_derived]
1517                    impl<'a, T, T2: Serialize, T3> ::optionable::Optionable for DeriveExample<'a, T, T2, T3>
1518                        where T: ::optionable::Optionable,
1519                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1520                              Cow<'a, T2>: ::optionable::Optionable,
1521                              <Cow<'a, T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1522                    {
1523                        type Optioned = DeriveExampleOpt<'a, T,T2,T3>;
1524                    }
1525
1526                    #[automatically_derived]
1527                    impl<'a, T, T2: Serialize, T3> ::optionable::Optionable for DeriveExampleOpt<'a ,T, T2, T3>
1528                        where T: ::optionable::Optionable,
1529                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1530                              Cow<'a, T2>: ::optionable::Optionable,
1531                              <Cow<'a, T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1532                    {
1533                        type Optioned = DeriveExampleOpt<'a, T, T2, T3>;
1534                    }
1535
1536                    #[automatically_derived]
1537                    impl <'a, T, T2:Serialize, T3> ::optionable::OptionableConvert for DeriveExample<'a, T, T2, T3>
1538                        where T: ::optionable::OptionableConvert,
1539                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1540                              Cow<'a, T2>: ::optionable::OptionableConvert,
1541                              <Cow<'a, T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1542                    {
1543                        fn into_optioned (self) -> DeriveExampleOpt<'a, T, T2, T3> {
1544                            DeriveExampleOpt::<'a, T, T2, T3> {
1545                                output: Some(::optionable::OptionableConvert::into_optioned(self.output)),
1546                                input: Some(::optionable::OptionableConvert::into_optioned(self.input)),
1547                                extra: self.extra
1548                            }
1549                        }
1550
1551                         fn try_from_optioned(value: DeriveExampleOpt<'a, T, T2, T3> ) -> Result <Self, ::optionable::Error> {
1552                             Ok(Self{
1553                                output: ::optionable::OptionableConvert::try_from_optioned(value.output.ok_or(::optionable::Error { missing_field: "output" })?)?,
1554                                input: ::optionable::OptionableConvert::try_from_optioned(value.input.ok_or(::optionable::Error { missing_field: "input" })?)?,
1555                                extra: value.extra
1556                            })
1557                        }
1558
1559                        fn merge(&mut self, other: DeriveExampleOpt<'a, T, T2, T3> ) -> Result<(), ::optionable::Error> {
1560                            if let Some(other_value) = other.output {
1561                                ::optionable::OptionableConvert::merge(&mut self.output, other_value)?;
1562                            }
1563                            if let Some(other_value) = other.input {
1564                                ::optionable::OptionableConvert::merge(&mut self.input, other_value)?;
1565                            }
1566                            self.extra=other.extra;
1567                            Ok(())
1568                        }
1569                    }
1570
1571
1572                    #[automatically_derived]
1573                    impl <'a, T, T2:Serialize, T3> ::optionable::OptionedConvert<DeriveExample<'a, T, T2, T3> > for DeriveExampleOpt<'a, T, T2, T3>
1574                        where T: ::optionable::OptionableConvert,
1575                              <T as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize,
1576                              Cow<'a, T2>: ::optionable::OptionableConvert,
1577                              <Cow<'a, T2> as ::optionable::Optionable>::Optioned: Sized + serde::de::DeserializeOwned + Serialize
1578                    {
1579                        fn from_optionable(value: DeriveExample<'a, T, T2, T3>) -> Self {
1580                            ::optionable::OptionableConvert::into_optioned(value)
1581                        }
1582
1583                        fn try_into_optionable(self) -> Result<DeriveExample<'a, T, T2, T3>, ::optionable::Error> {
1584                            ::optionable::OptionableConvert::try_from_optioned(self)
1585                        }
1586
1587                        fn merge_into(self, other: &mut DeriveExample<'a, T, T2, T3>) -> Result<(), ::optionable::Error> {
1588                            ::optionable::OptionableConvert::merge(other, self)
1589                        }
1590                    }
1591                },
1592            },
1593            TestCase {
1594                input: quote! {
1595                    #[derive(Optionable)]
1596                    enum DeriveExample {
1597                        Unit,
1598                        Plain(String),
1599                        Address{street: String, number: u32},
1600                        Address2(String,u32),
1601                    }
1602                },
1603                output: quote! {
1604                    enum DeriveExampleOpt {
1605                        Unit,
1606                        Plain( Option<String> ),
1607                        Address{ street: Option<String>, number:Option<u32> },
1608                        Address2( Option<String>, Option<u32> )
1609                    }
1610
1611                    #[automatically_derived]
1612                    impl ::optionable::Optionable for DeriveExample {
1613                        type Optioned = DeriveExampleOpt;
1614                    }
1615
1616                    #[automatically_derived]
1617                    impl ::optionable::Optionable for DeriveExampleOpt {
1618                        type Optioned = DeriveExampleOpt;
1619                    }
1620
1621                    #[automatically_derived]
1622                    impl ::optionable::OptionableConvert for DeriveExample {
1623                        fn into_optioned (self) -> DeriveExampleOpt {
1624                            match self{
1625                                Self::Unit => DeriveExampleOpt::Unit,
1626                                Self::Plain(self_0) => DeriveExampleOpt::Plain(
1627                                    Some(self_0)
1628                                ),
1629                                Self::Address{street: self_street, number: self_number} => DeriveExampleOpt::Address{
1630                                    street: Some(self_street),
1631                                    number: Some(self_number)
1632                                },
1633                                Self::Address2(self_0, self_1) => DeriveExampleOpt::Address2(
1634                                    Some(self_0),
1635                                    Some(self_1)
1636                                )
1637                            }
1638                        }
1639
1640                         fn try_from_optioned(other: DeriveExampleOpt) -> Result <Self, ::optionable::Error> {
1641                            Ok (match other {
1642                                DeriveExampleOpt::Unit => Self::Unit,
1643                                DeriveExampleOpt::Plain(other_0) => Self::Plain(
1644                                    other_0.ok_or(::optionable::Error { missing_field: "0" })?
1645                                ),
1646                                DeriveExampleOpt::Address{street: other_street, number: other_number} => Self::Address{
1647                                    street: other_street.ok_or(::optionable::Error { missing_field: "street" })?,
1648                                    number: other_number.ok_or(::optionable::Error { missing_field: "number" })?
1649                                },
1650                                DeriveExampleOpt::Address2(other_0, other_1) => Self::Address2(
1651                                    other_0.ok_or(::optionable::Error { missing_field: "0"})?,
1652                                    other_1.ok_or(::optionable::Error { missing_field: "1"})?)
1653                            })
1654                        }
1655
1656                        fn merge(&mut self, other: DeriveExampleOpt) -> Result<(), ::optionable::Error> {
1657                            match other {
1658                                DeriveExampleOpt::Unit => {
1659                                    if let Self::Unit = self {} else {
1660                                        *self = Self::try_from_optioned(DeriveExampleOpt::Unit)?;
1661                                    }
1662                                },
1663                                DeriveExampleOpt::Plain(other_0) => {
1664                                    if let Self::Plain(self_0) = self{
1665                                        if let Some(other_value) = other_0 {
1666                                            *self_0 = other_value;
1667                                        }
1668                                    } else {
1669                                        *self = Self::try_from_optioned(DeriveExampleOpt::Plain(other_0))?;
1670                                    }
1671                                },
1672                                DeriveExampleOpt::Address{street: other_street, number: other_number} => {
1673                                    if let Self::Address{street: self_street, number: self_number}  = self{
1674                                        if let Some(other_value) = other_street {
1675                                            *self_street = other_value;
1676                                        }
1677                                        if let Some(other_value) = other_number {
1678                                            *self_number = other_value;
1679                                        }
1680                                    } else {
1681                                        *self = Self::try_from_optioned(DeriveExampleOpt::Address{street: other_street, number: other_number})?;
1682                                    }
1683                                },
1684                                DeriveExampleOpt::Address2(other_0, other_1) => {
1685                                    if let Self::Address2(self_0, self_1) = self{
1686                                        if let Some(other_value) = other_0 {
1687                                            *self_0 = other_value;
1688                                        }
1689                                        if let Some(other_value) = other_1 {
1690                                            *self_1 = other_value;
1691                                        }
1692                                    } else {
1693                                        *self = Self::try_from_optioned(DeriveExampleOpt::Address2(other_0, other_1))?;
1694                                    }
1695                                }
1696                            }
1697                            Ok(())
1698                        }
1699                    }
1700
1701                    #[automatically_derived]
1702                    impl ::optionable::OptionedConvert<DeriveExample> for DeriveExampleOpt {
1703                        fn from_optionable(value: DeriveExample) -> Self {
1704                            ::optionable::OptionableConvert::into_optioned(value)
1705                        }
1706
1707                        fn try_into_optionable(self) -> Result<DeriveExample, ::optionable::Error> {
1708                            ::optionable::OptionableConvert::try_from_optioned(self)
1709                        }
1710
1711                        fn merge_into(self, other: &mut DeriveExample) -> Result<(), ::optionable::Error> {
1712                            ::optionable::OptionableConvert::merge(other, self)
1713                        }
1714                    }
1715                },
1716            },
1717            TestCase {
1718                input: quote! {
1719                    #[derive(Optionable)]
1720                    enum DeriveExample {
1721                        Unit,
1722                        Unit2,
1723                        Unit3
1724                    }
1725                },
1726                output: quote! {
1727                    #[automatically_derived]
1728                    impl ::optionable::Optionable for DeriveExample {
1729                        type Optioned = Self;
1730                    }
1731
1732                    #[automatically_derived]
1733                    impl ::optionable::OptionableConvert for DeriveExample {
1734                        fn into_optioned(self) -> DeriveExample{
1735                            self
1736                        }
1737
1738                        fn try_from_optioned(value: Self::Optioned) -> Result <Self , ::optionable::Error> {
1739                            Ok (value)
1740                        }
1741
1742                        fn merge (&mut self , other: Self::Optioned) -> Result <() , ::optionable::Error> {
1743                            *self = other;
1744                            Ok(())
1745                        }
1746                    }
1747                },
1748            },
1749        ];
1750        for tc in tcs {
1751            let input = syn::parse2(tc.input).unwrap();
1752            let output = derive_optionable(input, None).unwrap();
1753            println!("{output}");
1754            assert_eq!(tc.output.to_string(), output.to_string());
1755        }
1756    }
1757
1758    #[test]
1759    #[allow(clippy::too_many_lines)]
1760    /// Tests of the crate replacement settings available via codegen settings only
1761    fn test_crate_replacement() {
1762        let tcs = vec![TestCase {
1763            input: quote! {
1764                #[derive(Optionable)]
1765                struct DeriveExample {
1766                    name: crate::Name,
1767                    pub surname: Box<crate::SurName>,
1768                }
1769            },
1770            output: quote! {
1771                struct DeriveExampleOpt {
1772                    name: Option< <::testcrate::Name as crate::Optionable>::Optioned>,
1773                    pub surname: Option< <Box<::testcrate::SurName> as crate::Optionable>::Optioned>
1774                }
1775
1776                #[automatically_derived]
1777                impl crate::Optionable for crate_prefix::DeriveExample {
1778                    type Optioned = DeriveExampleOpt;
1779                }
1780
1781                #[automatically_derived]
1782                impl crate::Optionable for DeriveExampleOpt {
1783                    type Optioned = DeriveExampleOpt;
1784                }
1785
1786                #[automatically_derived]
1787                impl crate::OptionableConvert for crate_prefix::DeriveExample {
1788                    fn into_optioned (self) -> DeriveExampleOpt {
1789                        DeriveExampleOpt  {
1790                            name: Some(crate::OptionableConvert::into_optioned(self.name)),
1791                            surname: Some(crate::OptionableConvert::into_optioned(self.surname))
1792                        }
1793                    }
1794
1795                    fn try_from_optioned(value: DeriveExampleOpt ) -> Result <Self, crate::Error> {
1796                        Ok(Self{
1797                            name: crate::OptionableConvert::try_from_optioned(value.name.ok_or(crate::Error { missing_field: "name" })?)?,
1798                            surname: crate::OptionableConvert::try_from_optioned(value.surname.ok_or(crate::Error { missing_field: "surname" })?)?
1799                        })
1800                    }
1801
1802                    fn merge(&mut self, other: DeriveExampleOpt ) -> Result<(), crate::Error> {
1803                        if let Some(other_value) = other.name {
1804                             crate::OptionableConvert::merge(&mut self.name, other_value)?;
1805                        }
1806                        if let Some(other_value) = other.surname {
1807                             crate::OptionableConvert::merge(&mut self.surname, other_value)?;
1808                        }
1809                        Ok(())
1810                    }
1811                }
1812
1813                #[automatically_derived]
1814                impl crate::OptionedConvert<crate_prefix::DeriveExample> for DeriveExampleOpt {
1815                    fn from_optionable(value: crate_prefix::DeriveExample) -> Self {
1816                        crate::OptionableConvert::into_optioned(value)
1817                    }
1818
1819                    fn try_into_optionable(self) -> Result<crate_prefix::DeriveExample, crate::Error> {
1820                        crate::OptionableConvert::try_from_optioned(self)
1821                    }
1822
1823                    fn merge_into(self, other: &mut crate_prefix::DeriveExample) -> Result<(), crate::Error> {
1824                       crate::OptionableConvert::merge(other, self)
1825                    }
1826                }
1827            },
1828        }];
1829        for tc in tcs {
1830            let input = syn::parse2(tc.input).unwrap();
1831            let output = derive_optionable(
1832                input,
1833                Some(&CodegenSettings {
1834                    ty_prefix: Some(Path::from_string("crate_prefix").unwrap()),
1835                    optionable_crate_name: Path::from_string("crate").unwrap(),
1836                    input_crate_replacement: Some(parse_quote!(testcrate)),
1837                }),
1838            )
1839            .unwrap();
1840            assert_eq!(tc.output.to_string(), output.to_string());
1841        }
1842    }
1843}