optionable_codegen/
lib.rs

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