memflow_derive/
lib.rs

1mod batcher;
2
3use darling::{ast::NestedMeta, FromMeta};
4use proc_macro::TokenStream;
5use proc_macro_crate::*;
6use quote::{format_ident, quote};
7use syn::{parse_macro_input, Data, DeriveInput, Fields, ItemFn};
8
9/// Auto implement a function to batch read fields from a struct.
10///
11/// # Example
12///
13/// ```rust,ignore
14/// # use ::memflow::prelude::v1::*;
15///
16/// #[derive(Batcher)]
17/// struct FooBar {
18///    #[batch(offset = 0x20)]
19///    foo: u32,
20///    #[batch(offset = 0x1f0)]
21///    bar: u32,
22/// }
23/// ```
24#[proc_macro_derive(Batcher, attributes(batch))]
25pub fn batcher_derive(input: TokenStream) -> TokenStream {
26    batcher::batcher_derive(input)
27}
28
29#[derive(Debug, FromMeta)]
30struct ConnectorFactoryArgs {
31    name: String,
32    #[darling(default)]
33    version: Option<String>,
34    #[darling(default)]
35    description: Option<String>,
36    #[darling(default)]
37    help_fn: Option<String>,
38    #[darling(default)]
39    target_list_fn: Option<String>,
40    #[darling(default)]
41    accept_input: bool,
42    #[darling(default)]
43    return_wrapped: bool,
44    #[darling(default)]
45    no_default_cache: bool,
46}
47
48#[derive(Debug, FromMeta)]
49struct OsFactoryArgs {
50    name: String,
51    #[darling(default)]
52    version: Option<String>,
53    #[darling(default)]
54    description: Option<String>,
55    #[darling(default)]
56    help_fn: Option<String>,
57    #[darling(default)]
58    accept_input: bool,
59    #[darling(default)]
60    return_wrapped: bool,
61}
62
63fn validate_plugin_name(name: &str) {
64    if !name
65        .chars()
66        .all(|c| char::is_alphanumeric(c) || c == '-' || c == '_')
67    {
68        panic!("plugin name must only contain alphanumeric characters");
69    }
70}
71
72/// Creates a memflow connector plugin.
73/// This function takes care of supplying all necessary underlying structures
74/// for exposing a memflow connector plugin in the form of a dylib.
75///
76/// Remarks:
77///
78/// We should add conditional compilation for the crate-type here
79/// so our rust libraries who use a connector wont export those functions
80/// again by themselves (e.g. the ffi).
81///
82/// This would also lead to possible duplicated symbols if
83/// multiple connectors are imported.
84///
85/// See <https://github.com/rust-lang/rust/issues/20267> for the tracking issue.
86///
87/// #[cfg(crate_type = "cdylib")]
88///
89/// Macro Parameters:
90///
91/// `name` - The name of the plugin
92/// `version` - The version of the plugin
93/// `description` - Short description of the plugin
94/// `help_fn` - Name of the function that provides a help text to the user
95/// `target_list_fn` - Name of the function that provides a list of all targets to the user
96/// `accept_input` - Wether or not this Connector is able to accept an Os-Plugin as an input
97/// `return_wrapped` - Wether or not the return value is an already wrapped cglue object or if the macro needs to construct it
98/// `no_default_cache` - Disables the default caching behavior if no cache configuration is supplied by the user.
99///
100/// Caching:
101///
102/// By default the proc macro will call `memflow::plugins::connector::create_instance` internally which will handle the caching functionality.
103/// Either the user did not specify any caching, which results in the default caching configuration being used, or the user
104/// did choose a custom caching configuration which will override the default caching configuration.
105///
106/// In case `no_default_cache` is used the default behavior will be to use no caching. If the user supplies a cache configuration even
107/// if `no_default_cache` is set the `memflow::plugins::connector::create_instance` function will still instantiate the requested configuration.
108///
109/// In case `return_wrapped` is set to true the caching behavior has to be handled by the end user simply by
110/// calling `memflow::plugins::connector::create_instance` with the appropiate arguments.
111///
112/// Examples:
113///
114/// Simple usage:
115/// ```rust,ignore
116/// # use ::memflow::prelude::v1::*;
117/// # use ::memflow::dummy::*;
118/// #[connector(name = "dummy_conn", version = "1.0.0", description = "Dummy Plugin for Testing purposes")]
119/// pub fn create_connector(_args: &ConnectorArgs) -> Result<DummyMemory> {
120///     Ok(DummyMemory::new(size::mb(16)))
121/// }
122/// ```
123///
124/// Disable default caching:
125/// ```rust,ignore
126/// # use ::memflow::prelude::v1::*;
127/// # use ::memflow::dummy::*;
128/// #[connector(name = "dummy_conn", no_default_cache = true)]
129/// pub fn create_connector(_args: &ConnectorArgs) -> Result<DummyMemory> {
130///     Ok(DummyMemory::new(size::mb(16)))
131/// }
132/// ```
133///
134/// Custom help function:
135/// ```rust,ignore
136/// # use ::memflow::prelude::v1::*;
137/// # use ::memflow::dummy::*;
138/// #[connector(name = "dummy_conn", help_fn = "help")]
139/// pub fn create_connector(_args: &ConnectorArgs) -> Result<DummyMemory> {
140///     Ok(DummyMemory::new(size::mb(16)))
141/// }
142///
143/// pub fn help() -> String {
144///     "Dummy Plugin for Testing purposes".to_string()
145/// }
146/// ```
147///
148/// Custom target list function:
149/// ```rust,ignore
150/// # use ::memflow::prelude::v1::*;
151/// # use ::memflow::dummy::*;
152/// # use std::vec::Vec;
153/// #[connector(name = "dummy_conn", target_list_fn = "target_list")]
154/// pub fn create_connector(_args: &ConnectorArgs) -> Result<DummyMemory> {
155///     Ok(DummyMemory::new(size::mb(16)))
156/// }
157///
158/// pub fn target_list() -> Result<Vec<TargetInfo>> {
159///     Ok(Vec::new())
160/// }
161/// ```
162///
163/// Wrapped return with manually created connector instance:
164/// ```rust,ignore
165/// # use ::memflow::prelude::v1::*;
166/// # use ::memflow::dummy::*;
167/// #[connector(name = "dummy_conn", return_wrapped = true)]
168/// pub fn create_connector(
169///     args: &ConnectorArgs,
170///     lib: LibArc,
171/// ) -> Result<ConnectorInstanceArcBox<'static>> {
172///     let connector = DummyMemory::new(size::mb(16));
173///     Ok(memflow::plugins::connector::create_instance(connector, lib, args, false))
174/// }
175/// ```
176///
177/// Connector with input parameter:
178/// ```rust,ignore
179/// # use ::memflow::prelude::v1::*;
180/// # use ::memflow::dummy::*;
181/// #[connector(name = "dummy_conn", accept_input = true)]
182/// pub fn create_connector(
183///     _args: &ConnectorArgs,
184///     _os: Option<OsInstanceArcBox<'static>>,
185/// ) -> Result<DummyMemory> {
186///     Ok(DummyMemory::new(size::mb(16)))
187/// }
188/// ```
189///
190/// Connector with input parameter and manually created connector instance:
191/// ```rust,ignore
192/// # use ::memflow::prelude::v1::*;
193/// # use ::memflow::dummy::*;
194/// #[connector(name = "dummy_conn", accept_input = true, return_wrapped = true)]
195/// pub fn create_connector<'a>(
196///     args: &ConnectorArgs,
197///     _os: Option<OsInstanceArcBox<'static>>,
198///     lib: LibArc,
199/// ) -> Result<ConnectorInstanceArcBox<'static>> {
200///     let connector = DummyMemory::new(size::mb(16));
201///     Ok(memflow::plugins::connector::create_instance(connector, lib, args, false))
202/// }
203/// ```
204#[proc_macro_attribute]
205pub fn connector(args: TokenStream, input: TokenStream) -> TokenStream {
206    let crate_path = crate_path();
207
208    let attr_args = match NestedMeta::parse_meta_list(args.into()) {
209        Ok(v) => v,
210        Err(e) => return TokenStream::from(darling::Error::from(e).write_errors()),
211    };
212    let args = match ConnectorFactoryArgs::from_list(&attr_args) {
213        Ok(v) => v,
214        Err(e) => return TokenStream::from(e.write_errors()),
215    };
216
217    let connector_name = args.name;
218    validate_plugin_name(&connector_name);
219
220    let version_gen = args
221        .version
222        .map_or_else(|| quote! { env!("CARGO_PKG_VERSION") }, |v| quote! { #v });
223
224    let description_gen = args.description.map_or_else(
225        || quote! { env!("CARGO_PKG_DESCRIPTION") },
226        |d| quote! { #d },
227    );
228
229    let help_gen = if args.help_fn.is_some() {
230        quote! { Some(mf_help_callback) }
231    } else {
232        quote! { None }
233    };
234
235    let target_list_gen = if args.target_list_fn.is_some() {
236        quote! { Some(mf_target_list_callback) }
237    } else {
238        quote! { None }
239    };
240
241    let connector_descriptor: proc_macro2::TokenStream =
242        ["MEMFLOW_CONNECTOR_", &connector_name.to_uppercase()]
243            .concat()
244            .parse()
245            .unwrap();
246
247    let func = parse_macro_input!(input as ItemFn);
248    let func_name = &func.sig.ident;
249
250    let func_accept_input = args.accept_input;
251    let func_return_wrapped = args.return_wrapped;
252
253    let no_default_cache = args.no_default_cache;
254
255    // create wrapping function according to input/output configuration
256    #[allow(clippy::collapsible_else_if)]
257    let create_fn_gen_inner = if func_accept_input {
258        if !func_return_wrapped {
259            // args + os
260            quote! {
261                #crate_path::plugins::wrap_with_input(args, os.into(), lib, logger, out, |a, os, lib| {
262                    Ok(#crate_path::plugins::connector::create_instance(#func_name(a, os)?, lib, a, #no_default_cache))
263                })
264            }
265        } else {
266            // args + os + lib
267            quote! {
268                #crate_path::plugins::wrap_with_input(args, os.into(), lib, logger, out, #func_name)
269            }
270        }
271    } else {
272        if !func_return_wrapped {
273            // args
274            quote! {
275                #crate_path::plugins::wrap(args, lib, logger, out, |a, lib| {
276                    Ok(#crate_path::plugins::connector::create_instance(#func_name(a)?, lib, a, #no_default_cache))
277                })
278            }
279        } else {
280            // args + lib
281            quote! {
282                #crate_path::plugins::wrap(args, lib, logger, out, #func_name)
283            }
284        }
285    };
286
287    let create_fn_gen = quote! {
288            #[doc(hidden)]
289            extern "C" fn mf_create(
290                args: Option<&#crate_path::plugins::connector::ConnectorArgs>,
291                os: #crate_path::cglue::option::COption<#crate_path::plugins::os::OsInstanceArcBox<'static>>,
292                lib: #crate_path::plugins::LibArc,
293                logger: Option<&'static #crate_path::plugins::PluginLogger>,
294                out: &mut #crate_path::plugins::connector::MuConnectorInstanceArcBox<'static>
295            ) -> i32 {
296                #create_fn_gen_inner
297            }
298    };
299
300    let help_fn_gen = args.help_fn.map(|v| v.parse().unwrap()).map_or_else(
301        proc_macro2::TokenStream::new,
302        |func_name: proc_macro2::TokenStream| {
303            quote! {
304                #[doc(hidden)]
305                extern "C" fn mf_help_callback(
306                    mut callback: #crate_path::plugins::HelpCallback,
307                ) {
308                    let helpstr = #func_name();
309                    let _ = callback.call(helpstr.into());
310                }
311            }
312        },
313    );
314
315    let target_list_fn_gen = args.target_list_fn.map(|v| v.parse().unwrap()).map_or_else(
316        proc_macro2::TokenStream::new,
317        |func_name: proc_macro2::TokenStream| {
318            quote! {
319                #[doc(hidden)]
320                extern "C" fn mf_target_list_callback(
321                    mut callback: #crate_path::plugins::TargetCallback,
322                ) -> i32 {
323                    #func_name()
324                        .map(|mut targets| {
325                            targets
326                                .into_iter()
327                                .take_while(|t| callback.call(t.clone()))
328                                .for_each(|_| ());
329                        })
330                        .into_int_result()
331                }
332            }
333        },
334    );
335
336    let gen = quote! {
337        #[doc(hidden)]
338        #[no_mangle]
339        pub static #connector_descriptor: #crate_path::plugins::ConnectorDescriptor = #crate_path::plugins::ConnectorDescriptor {
340            plugin_version: #crate_path::plugins::MEMFLOW_PLUGIN_VERSION,
341            accept_input: #func_accept_input,
342            input_layout: <<#crate_path::plugins::LoadableConnector as #crate_path::plugins::Loadable>::CInputArg as #crate_path::abi_stable::StableAbi>::LAYOUT,
343            output_layout: <<#crate_path::plugins::LoadableConnector as #crate_path::plugins::Loadable>::Instance as #crate_path::abi_stable::StableAbi>::LAYOUT,
344            name: #crate_path::cglue::CSliceRef::from_str(#connector_name),
345            version: #crate_path::cglue::CSliceRef::from_str(#version_gen),
346            description: #crate_path::cglue::CSliceRef::from_str(#description_gen),
347            help_callback: #help_gen,
348            target_list_callback: #target_list_gen,
349            create: mf_create,
350        };
351
352        #create_fn_gen
353
354        #help_fn_gen
355
356        #target_list_fn_gen
357
358        #func
359    };
360
361    gen.into()
362}
363
364/// Creates a memflow os plugin.
365/// This function takes care of supplying all necessary underlying structures
366/// for exposing a memflow os plugin in the form of a dylib.
367///
368/// Macro Parameters:
369///
370/// `name` - The name of the plugin
371/// `version` - The version of the plugin
372/// `description` - Short description of the plugin
373/// `help_fn` - Name of the function that provides a help text to the user
374/// `accept_input` - Wether or not this Os-Plugin is able to accept a connector as an input
375/// `return_wrapped` - Wether or not the return value is an already wrapped cglue object or if the macro needs to construct it
376///
377/// Examples:
378///
379/// Simple usage:
380/// ```rust,ignore
381/// # use ::memflow::prelude::v1::*;
382/// # use ::memflow::dummy::*;
383/// #[os(name = "dummy_os", version = "1.0.0", description = "Dummy Plugin for Testing purposes")]
384/// pub fn create_os(
385///     _args: &OsArgs,
386/// ) -> Result<DummyOs> {
387///     let phys_mem = DummyMemory::new(size::mb(16));
388///     Ok(DummyOs::new(phys_mem))
389/// }
390///
391/// ```
392/// Custom help function:
393/// ```rust,ignore
394/// # use ::memflow::prelude::v1::*;
395/// # use ::memflow::dummy::*;
396/// #[os(name = "dummy_os", help_fn = "help")]
397/// pub fn create_os(
398///     _args: &OsArgs,
399/// ) -> Result<DummyOs> {
400///     let phys_mem = DummyMemory::new(size::mb(16));
401///     Ok(DummyOs::new(phys_mem))
402/// }
403///
404/// pub fn help() -> String {
405///     "Dummy Plugin for Testing purposes".to_string()
406/// }
407/// ```
408///
409/// Wrapped return with manually created os instance:
410/// ```rust,ignore
411/// # use ::memflow::prelude::v1::*;
412/// # use ::memflow::dummy::*;
413/// #[os(name = "dummy_os", return_wrapped = true)]
414/// pub fn create_os(
415///     args: &OsArgs,
416///     lib: LibArc,
417/// ) -> Result<OsInstanceArcBox<'static>> {
418///     let phys_mem = DummyMemory::new(size::mb(16));
419///     let os = DummyOs::new(phys_mem);
420///     Ok(memflow::plugins::os::create_instance(os, lib, args))
421/// }
422/// ```
423///
424/// Os with input parameter:
425/// ```rust,ignore
426/// # use ::memflow::prelude::v1::*;
427/// # use ::memflow::dummy::*;
428/// #[os(name = "dummy_os", accept_input = true)]
429/// pub fn create_os(
430///     args: &OsArgs,
431///     _connector: Option<ConnectorInstanceArcBox<'static>>,
432/// ) -> Result<DummyOs> {
433///     let phys_mem = DummyMemory::new(size::mb(16));
434///     Ok(DummyOs::new(phys_mem))
435/// }
436/// ```
437///
438/// Os with input parameter and manually created os instance:
439/// ```rust,ignore
440/// # use ::memflow::prelude::v1::*;
441/// # use ::memflow::dummy::*;
442/// #[os(name = "dummy_os", accept_input = true, return_wrapped = true)]
443/// pub fn create_os(
444///     args: &OsArgs,
445///     _connector: Option<ConnectorInstanceArcBox<'static>>,
446///     lib: LibArc,
447/// ) -> Result<OsInstanceArcBox<'static>> {
448///     let phys_mem = DummyMemory::new(size::mb(16));
449///     let os = DummyOs::new(phys_mem);
450///     Ok(memflow::plugins::os::create_instance(os, lib, args))
451/// }
452/// ```
453#[proc_macro_attribute]
454pub fn os(args: TokenStream, input: TokenStream) -> TokenStream {
455    let crate_path = crate_path();
456
457    let attr_args = match NestedMeta::parse_meta_list(args.into()) {
458        Ok(v) => v,
459        Err(e) => return TokenStream::from(darling::Error::from(e).write_errors()),
460    };
461    let args = match OsFactoryArgs::from_list(&attr_args) {
462        Ok(v) => v,
463        Err(e) => return TokenStream::from(e.write_errors()),
464    };
465
466    let os_name = args.name;
467    validate_plugin_name(&os_name);
468
469    let version_gen = args
470        .version
471        .map_or_else(|| quote! { env!("CARGO_PKG_VERSION") }, |v| quote! { #v });
472
473    let description_gen = args.description.map_or_else(
474        || quote! { env!("CARGO_PKG_DESCRIPTION") },
475        |d| quote! { #d },
476    );
477
478    let help_gen = if args.help_fn.is_some() {
479        quote! { Some(mf_help_callback) }
480    } else {
481        quote! { None }
482    };
483
484    let os_descriptor: proc_macro2::TokenStream = ["MEMFLOW_OS_", &os_name.to_uppercase()]
485        .concat()
486        .parse()
487        .unwrap();
488
489    let func = parse_macro_input!(input as ItemFn);
490    let func_name = &func.sig.ident;
491
492    let func_accept_input = args.accept_input;
493    let func_return_wrapped = args.return_wrapped;
494
495    // create wrapping function according to input/output configuration
496    #[allow(clippy::collapsible_else_if)]
497    let create_fn_gen_inner = if func_accept_input {
498        if !func_return_wrapped {
499            // inputs: args + connector
500            quote! {
501                #crate_path::plugins::wrap_with_input(args, connector.into(), lib, logger, out, |a, os, lib| {
502                    Ok(#crate_path::plugins::os::create_instance(#func_name(a, os)?, lib, a))
503                })
504            }
505        } else {
506            // inputs: args + connector + lib
507            quote! {
508                #crate_path::plugins::wrap_with_input(args, connector.into(), lib, logger, out, #func_name)
509            }
510        }
511    } else {
512        if !func_return_wrapped {
513            // inputs: args
514            quote! {
515                #crate_path::plugins::wrap(args, lib, logger, out, |a, lib| {
516                    Ok(#crate_path::plugins::os::create_instance(#func_name(a)?, lib, a))
517                })
518            }
519        } else {
520            // inputs: args + lib
521            quote! {
522                #crate_path::plugins::wrap(args, lib, logger, out, #func_name)
523            }
524        }
525    };
526
527    let create_fn_gen = quote! {
528        #[doc(hidden)]
529        extern "C" fn mf_create(
530            args: Option<&#crate_path::plugins::os::OsArgs>,
531            connector: #crate_path::cglue::COption<#crate_path::plugins::connector::ConnectorInstanceArcBox<'static>>,
532            lib: #crate_path::plugins::LibArc,
533            logger: Option<&'static #crate_path::plugins::PluginLogger>,
534            out: &mut #crate_path::plugins::os::MuOsInstanceArcBox<'static>
535        ) -> i32 {
536            #create_fn_gen_inner
537        }
538    };
539
540    let help_fn_gen = args.help_fn.map(|v| v.parse().unwrap()).map_or_else(
541        proc_macro2::TokenStream::new,
542        |func_name: proc_macro2::TokenStream| {
543            quote! {
544                #[doc(hidden)]
545                extern "C" fn mf_help_callback(
546                    mut callback: #crate_path::plugins::HelpCallback,
547                ) {
548                    let helpstr = #func_name();
549                    let _ = callback.call(helpstr.into());
550                }
551            }
552        },
553    );
554
555    let gen = quote! {
556        #[doc(hidden)]
557        #[no_mangle]
558        pub static #os_descriptor: #crate_path::plugins::os::OsDescriptor = #crate_path::plugins::os::OsDescriptor {
559            plugin_version: #crate_path::plugins::MEMFLOW_PLUGIN_VERSION,
560            accept_input: #func_accept_input,
561            input_layout: <<#crate_path::plugins::os::LoadableOs as #crate_path::plugins::Loadable>::CInputArg as #crate_path::abi_stable::StableAbi>::LAYOUT,
562            output_layout: <<#crate_path::plugins::os::LoadableOs as #crate_path::plugins::Loadable>::Instance as #crate_path::abi_stable::StableAbi>::LAYOUT,
563            name: #crate_path::cglue::CSliceRef::from_str(#os_name),
564            version: #crate_path::cglue::CSliceRef::from_str(#version_gen),
565            description: #crate_path::cglue::CSliceRef::from_str(#description_gen),
566            help_callback: #help_gen,
567            target_list_callback: None, // non existent on Os Plugins
568            create: mf_create,
569        };
570
571        #create_fn_gen
572
573        #help_fn_gen
574
575        #func
576    };
577
578    gen.into()
579}
580
581/// Auto derive the `Pod` trait for structs.
582///
583/// The type is checked for requirements of the `Pod` trait:
584///
585/// * Be annotated with `repr(C)` or `repr(transparent)`.
586///
587/// * Have every field's type implement `Pod` itself.
588///
589/// * Not have any padding between its fields.
590///
591/// # Compile errors
592///
593/// Error reporting is not very ergonomic due to how errors are detected:
594///
595/// * `error[E0277]: the trait bound $TYPE: Pod is not satisfied`
596///
597///   The struct contains a field whose type does not implement `Pod`.
598///
599/// * `error[E0512]: cannot transmute between types of different sizes, or dependently-sized types`
600///
601///   This error means your struct has padding as its size is not equal to a byte array of length equal to the sum of the size of its fields.
602///
603/// * `error: no rules expected the token <`
604///
605///   The struct contains generic parameters which are not supported. It may still be possible to manually implement `Pod` but extra care should be taken to ensure its invariants are upheld.
606///
607/// # Remarks:
608/// This custom derive macro is required because the dataview proc macro searches for ::dataview::derive_pod!().
609/// See <https://github.com/CasualX/dataview/blob/master/derive_pod/lib.rs> for the original implementation.
610#[proc_macro_derive(Pod)]
611pub fn pod_derive(input: TokenStream) -> TokenStream {
612    let crate_path = crate_path();
613
614    format!("{crate_path}::dataview::derive_pod!{{ {input} }}")
615        .parse()
616        .unwrap()
617}
618
619#[proc_macro_derive(ByteSwap)]
620pub fn byteswap_derive(input: TokenStream) -> TokenStream {
621    let crate_path = crate_path();
622
623    let input = parse_macro_input!(input as DeriveInput);
624    let name = &input.ident;
625    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
626
627    let mut gen_inner = quote!();
628    match input.data {
629        Data::Struct(data) => match data.fields {
630            Fields::Named(named) => {
631                for field in named.named.iter() {
632                    let name = field.ident.as_ref().unwrap();
633                    gen_inner.extend(quote!(
634                        self.#name.byte_swap();
635                    ));
636                }
637            }
638            _ => unimplemented!(),
639        },
640        _ => unimplemented!(),
641    };
642
643    let gen = quote!(
644        impl #impl_generics #crate_path::types::byte_swap::ByteSwap for #name #ty_generics #where_clause {
645            fn byte_swap(&mut self) {
646                #gen_inner
647            }
648        }
649    );
650
651    gen.into()
652}
653
654fn crate_path() -> proc_macro2::TokenStream {
655    let (col, ident) = crate_path_ident();
656    quote!(#col #ident)
657}
658
659fn crate_path_ident() -> (Option<syn::token::PathSep>, proc_macro2::Ident) {
660    let found_crate = crate_name("memflow").expect("memflow found in `Cargo.toml`");
661    match found_crate {
662        FoundCrate::Itself => (None, format_ident!("memflow")), // we can use memflow instead of crate due to the alias in lib.rs
663        FoundCrate::Name(name) => (Some(Default::default()), format_ident!("{}", name)),
664    }
665}