Skip to main content

miniextendr_macros/
match_arg_keys.rs

1//! Write-time placeholder & symbol-name formatting for the match_arg pipeline.
2//!
3//! Tradeoff signpost: this module is the **wiring** between the
4//! `#[derive(MatchArg)]` proc macro (see `match_arg_derive`) and the
5//! wrapper writer's substitution pass. The `match.arg` codegen path
6//! deliberately splits responsibilities — the proc macro emits placeholders
7//! into the R wrapper, and the wrapper writer resolves them to a concrete `c("a",
8//! "b", ...)` literal (and the check's `aliases =` argument, if any) at
9//! write time using `MX_MATCH_ARG_CHOICES`. That
10//! split lets the variant list change without re-running `cargo expand` on
11//! every consumer. Compared to hand-rolling `match.arg` in a wrapper body,
12//! the user gets partial matching, R-visible defaults, and `@param` doc
13//! lines for free, without ever stringifying the variant list in source.
14//!
15//! All three placeholders (`choices_placeholder`, `aliases_placeholder`,
16//! `param_doc_placeholder`) share the same
17//! `{c_ident_without_prefix}_{r_param}` stem so the wrapper writer's pass
18//! can correlate them. Keep them together so the shape can't drift.
19//!
20//! The `c_ident_without_prefix` input has `C_` already stripped (or is a stem
21//! already, e.g. `MyType__method`). Callers that have a full `c_ident` should
22//! pass `c_ident.trim_start_matches("C_")`.
23//!
24//! All three helpers call `c_stem(...)` internally so callers may also pass a
25//! full `c_ident` (e.g. `"C_my_fn"`) — the `C_` prefix is normalized away.
26
27fn c_stem(c_ident: &str) -> &str {
28    c_ident.trim_start_matches("C_")
29}
30
31/// The `{r_param}` part of a parameter's placeholders: its Rust name
32/// (`rust_name`, [`crate::naming::ident_name`]) without leading underscores,
33/// also when it declares an R formal (#1842). The placeholders are replaced
34/// before R reads the text, and [`placeholder_ident_suffix`] makes Rust
35/// identifiers of them, so a declared formal, which may hold a `.`, never
36/// becomes part of one.
37pub(crate) fn param_key(rust_name: &str) -> String {
38    crate::r_wrapper_builder::normalize_r_arg_string(rust_name)
39}
40
41/// Start of every [`choices_placeholder`]. The shadowing pass
42/// (`r_shadowing`) reads a name with this prefix as a call to `c`, which is
43/// what the placeholder becomes.
44pub(crate) const CHOICES_PLACEHOLDER_PREFIX: &str = ".__MX_MATCH_ARG_CHOICES_";
45
46/// R-side placeholder that the wrapper writer resolves to a `c("a", "b", ...)` literal
47/// at write time. Substituted by `MX_MATCH_ARG_CHOICES` entries.
48pub(crate) fn choices_placeholder(c_ident: &str, r_param: &str) -> String {
49    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{2}{0}_{1}__", c_stem(c_ident),
                r_param, CHOICES_PLACEHOLDER_PREFIX))
    })format!(
50        "{CHOICES_PLACEHOLDER_PREFIX}{}_{}__",
51        c_stem(c_ident),
52        r_param
53    )
54}
55
56/// Start of every [`aliases_placeholder`].
57pub(crate) const ALIASES_PLACEHOLDER_PREFIX: &str = ".__MX_MATCH_ARG_ALIASES_";
58
59/// R-side placeholder for the trailing `aliases =` argument of a `match_arg`
60/// parameter's check (#1843), written as `, <placeholder>` after the other
61/// arguments. The wrapper writer replaces `, <placeholder>` with
62/// `, aliases = base::c("grey" = "gray")`, or with nothing when the type has
63/// no aliases (`registry::match_arg_aliases_arg`), from the same
64/// `MX_MATCH_ARG_CHOICES` entry as [`choices_placeholder`]. The macro can't
65/// tell which: `MatchArg::ALIASES` resolves at link time, as `CHOICES` does.
66pub(crate) fn aliases_placeholder(c_ident: &str, r_param: &str) -> String {
67    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{2}{0}_{1}__", c_stem(c_ident),
                r_param, ALIASES_PLACEHOLDER_PREFIX))
    })format!(
68        "{ALIASES_PLACEHOLDER_PREFIX}{}_{}__",
69        c_stem(c_ident),
70        r_param
71    )
72}
73
74/// R-side placeholder for the `@param` doc line, substituted by
75/// `MX_MATCH_ARG_PARAM_DOCS` entries at write time. See #210.
76pub(crate) fn param_doc_placeholder(c_ident: &str, r_param: &str) -> String {
77    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(".__MX_MATCH_ARG_PARAM_DOC_{0}_{1}__",
                c_stem(c_ident), r_param))
    })format!(
78        ".__MX_MATCH_ARG_PARAM_DOC_{}_{}__",
79        c_stem(c_ident),
80        r_param
81    )
82}
83
84/// Extract the unquoted form of a user-supplied `default = "..."` literal
85/// for a `match_arg` parameter.
86///
87/// The user writes the value as it appears in R source, so a string default
88/// is `default = "\"zstd\""` — the `String` we receive is `"zstd"` (with the
89/// quote chars). Strip the outer quotes if present; otherwise pass the raw
90/// value through unchanged. The write-time pass validates the result against
91/// the enum's `CHOICES` and panics on miss, so a malformed literal (e.g.
92/// `default = "1L"`) still surfaces as a clear error at wrapper generation.
93pub(crate) fn extract_match_arg_default(raw: &str) -> String {
94    raw.strip_prefix('"')
95        .and_then(|s| s.strip_suffix('"'))
96        .unwrap_or(raw)
97        .to_string()
98}
99
100/// Derive a safe Rust ident from a write-time placeholder string.
101///
102/// Strips surrounding underscores and turns every `.` into `_`, so a placeholder
103/// like `.__MX_MATCH_ARG_CHOICES_foo_bar__` becomes an ident suffix that quotes
104/// cleanly in emitted code.
105pub(crate) fn placeholder_ident_suffix(placeholder: &str) -> String {
106    placeholder.trim_matches('_').replace('.', "_")
107}
108
109/// Emit the `MX_MATCH_ARG_CHOICES` static + its linkme registration.
110///
111/// Factored so lib.rs (standalone fns) and miniextendr_impl.rs (impl methods)
112/// can't drift apart — both previously open-coded the same quote! block.
113///
114/// `preferred_default` is the unquoted form of the user's `default = "..."`
115/// (e.g. `"zstd"`). Pass `""` when the user supplied no default — the write
116/// pass then keeps the natural enum order.
117///
118/// `aliases_placeholder` is the parameter's [`aliases_placeholder`], which
119/// its check carries; the entry resolves it from the type's
120/// `MatchArg::ALIASES`.
121pub(crate) fn choices_entry_tokens(
122    cfg_attrs: &[syn::Attribute],
123    entry_ident: &syn::Ident,
124    placeholder: &str,
125    aliases_placeholder: &str,
126    choices_ty: &syn::Type,
127    preferred_default: &str,
128) -> proc_macro2::TokenStream {
129    {
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let cfg_attrs =
                match cfg_attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&cfg_attrs, &mut _s);
        }
    }
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "cfg_attr");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "not");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "target_arch");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::parse(&mut _s, "\"wasm32\"");
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "linkme");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "distributed_slice");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "registry");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s,
                                "MX_MATCH_ARG_CHOICES");
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "linkme");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "crate");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "linkme");
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s,
                        "non_upper_case_globals");
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "non_snake_case");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "static");
    ::quote::ToTokens::to_tokens(&entry_ident, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "registry");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "MatchArgChoicesEntry");
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "registry");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "MatchArgChoicesEntry");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "placeholder");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&placeholder, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "choices");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&choices_ty, &mut _s);
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "match_arg");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "MatchArg");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "CHOICES");
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "preferred_default");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&preferred_default, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "aliases_placeholder");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&aliases_placeholder, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "aliases");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&choices_ty, &mut _s);
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "match_arg");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "MatchArg");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "ALIASES");
            ::quote::__private::push_comma(&mut _s);
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote::quote! {
130        #(#cfg_attrs)*
131        #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_MATCH_ARG_CHOICES), linkme(crate = ::miniextendr_api::linkme))]
132        #[allow(non_upper_case_globals)]
133        #[allow(non_snake_case)]
134        static #entry_ident: ::miniextendr_api::registry::MatchArgChoicesEntry =
135            ::miniextendr_api::registry::MatchArgChoicesEntry {
136                placeholder: #placeholder,
137                choices: <#choices_ty as ::miniextendr_api::match_arg::MatchArg>::CHOICES,
138                preferred_default: #preferred_default,
139                aliases_placeholder: #aliases_placeholder,
140                aliases: <#choices_ty as ::miniextendr_api::match_arg::MatchArg>::ALIASES,
141            };
142    }
143}
144
145/// Emit the `MX_MATCH_ARG_PARAM_DOCS` static + its linkme registration.
146///
147/// `suffix` is the text the write pass puts after the rendered choice list,
148/// from `ParamAttrs::choice_doc_suffix` (", or NULL for no choice" for an
149/// `Option<T>` param, #1473; the omission note for `Missing<T>`, #1551).
150pub(crate) fn param_doc_entry_tokens(
151    cfg_attrs: &[syn::Attribute],
152    entry_ident: &syn::Ident,
153    placeholder: &str,
154    several_ok: bool,
155    suffix: &str,
156    choices_ty: &syn::Type,
157) -> proc_macro2::TokenStream {
158    {
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut cfg_attrs, i) = cfg_attrs.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let cfg_attrs =
                match cfg_attrs.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&cfg_attrs, &mut _s);
        }
    }
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "cfg_attr");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "not");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "target_arch");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::parse(&mut _s, "\"wasm32\"");
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "linkme");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "distributed_slice");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "registry");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s,
                                "MX_MATCH_ARG_PARAM_DOCS");
                            _s
                        });
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "linkme");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "crate");
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "linkme");
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s,
                        "non_upper_case_globals");
                    _s
                });
            _s
        });
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "non_snake_case");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "static");
    ::quote::ToTokens::to_tokens(&entry_ident, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "registry");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "MatchArgParamDocEntry");
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "registry");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "MatchArgParamDocEntry");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "placeholder");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&placeholder, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "several_ok");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&several_ok, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "suffix");
            ::quote::__private::push_colon(&mut _s);
            ::quote::ToTokens::to_tokens(&suffix, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "choices_str");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_or_or(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&choices_ty, &mut _s);
                    ::quote::__private::push_ident(&mut _s, "as");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "match_arg");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "MatchArg");
                    ::quote::__private::push_gt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "CHOICES");
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "iter");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "map");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_or(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "c");
                            ::quote::__private::push_or(&mut _s);
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "std");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "format");
                            ::quote::__private::push_bang(&mut _s);
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::parse(&mut _s, "\"\\\"{}\\\"\"");
                                    ::quote::__private::push_comma(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "c");
                                    _s
                                });
                            _s
                        });
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "collect");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "std");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "vec");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Vec");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_underscore(&mut _s);
                    ::quote::__private::push_shr(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        ::quote::__private::TokenStream::new());
                    ::quote::__private::push_dot(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "join");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::parse(&mut _s, "\", \"");
                            _s
                        });
                    _s
                });
            ::quote::__private::push_comma(&mut _s);
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote::quote! {
159        #(#cfg_attrs)*
160        #[cfg_attr(not(target_arch = "wasm32"), ::miniextendr_api::linkme::distributed_slice(::miniextendr_api::registry::MX_MATCH_ARG_PARAM_DOCS), linkme(crate = ::miniextendr_api::linkme))]
161        #[allow(non_upper_case_globals)]
162        #[allow(non_snake_case)]
163        static #entry_ident: ::miniextendr_api::registry::MatchArgParamDocEntry =
164            ::miniextendr_api::registry::MatchArgParamDocEntry {
165                placeholder: #placeholder,
166                several_ok: #several_ok,
167                suffix: #suffix,
168                choices_str: || {
169                    <#choices_ty as ::miniextendr_api::match_arg::MatchArg>::CHOICES
170                        .iter()
171                        .map(|c| ::std::format!("\"{}\"", c))
172                        .collect::<::std::vec::Vec<_>>()
173                        .join(", ")
174                },
175            };
176    }
177}