Skip to main content

capsec_macro/
lib.rs

1//! # capsec-macro
2//!
3//! Procedural macros for the `capsec` capability-based security system.
4//!
5//! Provides attribute macros:
6//!
7//! - [`requires`] — declares and validates a function's capability requirements.
8//! - [`deny`] — marks a function as capability-free for the lint tool.
9//! - [`main`] — injects `CapRoot` creation into a function entry point.
10//! - [`context`] — generates `Has<P>` impls and constructor for a capability context struct.
11//!
12//! These macros are re-exported by the `capsec` facade crate. You don't need to
13//! depend on `capsec-macro` directly.
14
15mod resolve;
16
17use proc_macro::TokenStream;
18use quote::{format_ident, quote};
19use syn::punctuated::Punctuated;
20use syn::{FnArg, ItemFn, ItemStruct, Meta, Pat, Token, Type, parse_macro_input};
21
22/// The set of known permission type names (bare idents).
23const KNOWN_PERMISSIONS: &[&str] = &[
24    "FsRead",
25    "FsWrite",
26    "FsAll",
27    "NetConnect",
28    "NetBind",
29    "NetAll",
30    "EnvRead",
31    "EnvWrite",
32    "Spawn",
33    "Ambient",
34];
35
36/// Defines a user-defined permission type for capability-based security.
37///
38/// Generates the `Permission` trait impl (with seal token), `Has<P>` impls for
39/// `Cap<P>` and `SendCap<P>`, and optionally `Subsumes` impls for permission hierarchies.
40///
41/// # Usage
42///
43/// ```rust,ignore
44/// #[capsec::permission]
45/// pub struct DbRead;
46///
47/// #[capsec::permission]
48/// pub struct DbWrite;
49///
50/// #[capsec::permission(subsumes = [DbRead, DbWrite])]
51/// pub struct DbAll;
52/// ```
53///
54/// # What it generates
55///
56/// For `#[capsec::permission] pub struct DbRead;`:
57/// - `impl Permission for DbRead` with the seal token
58/// - `impl Has<DbRead> for Cap<DbRead>`
59/// - `impl Has<DbRead> for SendCap<DbRead>`
60///
61/// For `#[capsec::permission(subsumes = [DbRead, DbWrite])] pub struct DbAll;`:
62/// - All of the above, plus:
63/// - `impl Subsumes<DbRead> for DbAll`
64/// - `impl Has<DbRead> for Cap<DbAll>` and `SendCap<DbAll>`
65/// - Same for `DbWrite`
66#[proc_macro_attribute]
67pub fn permission(attr: TokenStream, item: TokenStream) -> TokenStream {
68    let attr2: proc_macro2::TokenStream = attr.into();
69    let input = parse_macro_input!(item as ItemStruct);
70
71    match permission_inner(attr2, &input) {
72        Ok(tokens) => tokens.into(),
73        Err(e) => e.into_compile_error().into(),
74    }
75}
76
77fn permission_inner(
78    attr: proc_macro2::TokenStream,
79    input: &ItemStruct,
80) -> syn::Result<proc_macro2::TokenStream> {
81    // Validate: must be a unit struct (no fields)
82    match &input.fields {
83        syn::Fields::Unit => {}
84        _ => {
85            return Err(syn::Error::new_spanned(
86                input,
87                "#[capsec::permission] requires a unit struct (no fields)",
88            ));
89        }
90    }
91
92    // Reject generics
93    if !input.generics.params.is_empty() {
94        return Err(syn::Error::new_spanned(
95            &input.generics,
96            "#[capsec::permission] does not support generic structs",
97        ));
98    }
99
100    let struct_name = &input.ident;
101    let struct_vis = &input.vis;
102    let struct_attrs = &input.attrs;
103
104    // Parse subsumes = [...] from attribute
105    let subsumes = parse_subsumes(attr)?;
106
107    // Generate Permission impl with seal token
108    let permission_impl = quote! {
109        impl capsec_core::permission::Permission for #struct_name {
110            type __CapsecSeal = capsec_core::__private::SealProof;
111        }
112    };
113
114    // Note: Has<Self> for Cap<Self> and SendCap<Self> are already covered by
115    // the blanket impls in capsec_core::has:
116    //   impl<P: Permission> Has<P> for Cap<P>
117    //   impl<P: Permission> Has<P> for SendCap<P>
118    // So we only need to generate Subsumes-related Has impls.
119
120    // Generate Subsumes impls + Has<Sub> for Cap<Self>/SendCap<Self>
121    let subsumes_impls: Vec<_> = subsumes
122        .iter()
123        .map(|sub| {
124            quote! {
125                impl capsec_core::permission::Subsumes<#sub> for #struct_name {}
126
127                impl capsec_core::has::Has<#sub> for capsec_core::cap::Cap<#struct_name> {
128                    fn cap_ref(&self) -> capsec_core::cap::Cap<#sub> {
129                        capsec_core::cap::Cap::__capsec_new_derived()
130                    }
131                }
132
133                impl capsec_core::has::Has<#sub> for capsec_core::cap::SendCap<#struct_name> {
134                    fn cap_ref(&self) -> capsec_core::cap::Cap<#sub> {
135                        capsec_core::cap::Cap::__capsec_new_derived()
136                    }
137                }
138            }
139        })
140        .collect();
141
142    Ok(quote! {
143        #(#struct_attrs)*
144        #struct_vis struct #struct_name;
145
146        #permission_impl
147        #(#subsumes_impls)*
148    })
149}
150
151/// Parses `subsumes = [A, B, C]` from macro attribute tokens.
152fn parse_subsumes(attr: proc_macro2::TokenStream) -> syn::Result<Vec<syn::Path>> {
153    if attr.is_empty() {
154        return Ok(Vec::new());
155    }
156
157    // Parse as Meta::NameValue: subsumes = [...]
158    let meta: Meta = syn::parse2(attr)?;
159    match &meta {
160        Meta::NameValue(nv) if nv.path.is_ident("subsumes") => {
161            // The value should be an array expression: [A, B, C]
162            if let syn::Expr::Array(arr) = &nv.value {
163                let mut paths = Vec::new();
164                let mut seen = std::collections::HashSet::new();
165                for elem in &arr.elems {
166                    if let syn::Expr::Path(ep) = elem {
167                        let path_str = quote::quote!(#ep).to_string();
168                        if !seen.insert(path_str.clone()) {
169                            return Err(syn::Error::new_spanned(
170                                elem,
171                                format!("duplicate subsumes entry: {}", path_str),
172                            ));
173                        }
174                        paths.push(ep.path.clone());
175                    } else {
176                        return Err(syn::Error::new_spanned(
177                            elem,
178                            "expected a permission type path in subsumes list",
179                        ));
180                    }
181                }
182                Ok(paths)
183            } else {
184                Err(syn::Error::new_spanned(
185                    &nv.value,
186                    "expected an array [A, B, C] for subsumes",
187                ))
188            }
189        }
190        _ => Err(syn::Error::new_spanned(
191            &meta,
192            "expected `subsumes = [...]`",
193        )),
194    }
195}
196
197/// Declares the capability requirements of a function.
198///
199/// When all parameters use `impl Has<P>` bounds, the compiler already enforces
200/// the trait bounds and this macro emits only a `#[doc]` attribute.
201///
202/// When concrete parameter types are used (e.g., context structs), use `on = param`
203/// to identify the capability parameter. The macro emits a compile-time assertion
204/// that the parameter type implements `Has<P>` for each declared permission.
205///
206/// # Usage
207///
208/// ```rust,ignore
209/// // With impl bounds — no `on` needed
210/// #[capsec::requires(fs::read, net::connect)]
211/// fn sync_data(cap: &(impl Has<FsRead> + Has<NetConnect>)) -> Result<()> {
212///     // ...
213/// }
214///
215/// // With concrete context type — use `on = param`
216/// #[capsec::requires(fs::read, net::connect, on = ctx)]
217/// fn sync_data(config: &Config, ctx: &AppCtx) -> Result<()> {
218///     // ...
219/// }
220/// ```
221///
222/// # Supported permission paths
223///
224/// Both shorthand and explicit forms are accepted:
225///
226/// | Shorthand | Explicit | Permission type |
227/// |-----------|----------|-----------------|
228/// | `fs::read` | `FsRead` | `capsec_core::permission::FsRead` |
229/// | `fs::write` | `FsWrite` | `capsec_core::permission::FsWrite` |
230/// | `net::connect` | `NetConnect` | `capsec_core::permission::NetConnect` |
231/// | `net::bind` | `NetBind` | `capsec_core::permission::NetBind` |
232/// | `env::read` | `EnvRead` | `capsec_core::permission::EnvRead` |
233/// | `env::write` | `EnvWrite` | `capsec_core::permission::EnvWrite` |
234/// | `spawn` | `Spawn` | `capsec_core::permission::Spawn` |
235/// | `all` | `Ambient` | `capsec_core::permission::Ambient` |
236#[proc_macro_attribute]
237pub fn requires(attr: TokenStream, item: TokenStream) -> TokenStream {
238    let attr2: proc_macro2::TokenStream = attr.into();
239    let func = parse_macro_input!(item as ItemFn);
240
241    match requires_inner(attr2, &func) {
242        Ok(tokens) => tokens.into(),
243        Err(e) => e.into_compile_error().into(),
244    }
245}
246
247fn requires_inner(
248    attr: proc_macro2::TokenStream,
249    func: &ItemFn,
250) -> syn::Result<proc_macro2::TokenStream> {
251    let metas: Punctuated<Meta, Token![,]> =
252        syn::parse::Parser::parse2(Punctuated::parse_terminated, attr)?;
253
254    // Separate `on = param` from permission metas
255    let mut on_param: Option<syn::Ident> = None;
256    let mut perm_metas: Vec<&Meta> = Vec::new();
257
258    for meta in &metas {
259        if let Meta::NameValue(nv) = meta
260            && nv.path.is_ident("on")
261        {
262            if let syn::Expr::Path(ep) = &nv.value
263                && let Some(ident) = ep.path.get_ident()
264            {
265                on_param = Some(ident.clone());
266                continue;
267            }
268            return Err(syn::Error::new_spanned(&nv.value, "expected an identifier"));
269        }
270        perm_metas.push(meta);
271    }
272
273    // Resolve permission types
274    let mut cap_types = Vec::new();
275    for meta in &perm_metas {
276        cap_types.push(resolve::meta_to_permission_type(meta)?);
277    }
278
279    // Build doc string
280    let doc_string = format!(
281        "capsec::requires({})",
282        cap_types
283            .iter()
284            .map(|c| quote!(#c).to_string())
285            .collect::<Vec<_>>()
286            .join(", ")
287    );
288
289    // Check if any parameter uses `impl` trait bounds
290    let has_impl_bounds = func.sig.inputs.iter().any(|arg| {
291        if let FnArg::Typed(pat_type) = arg {
292            contains_impl_trait(&pat_type.ty)
293        } else {
294            false
295        }
296    });
297
298    // Build assertion block if needed
299    let assertion = if let Some(ref param_name) = on_param {
300        // Find the parameter and extract its type
301        let param_type = find_param_type(&func.sig, param_name)?;
302        let inner_type = unwrap_references(&param_type);
303
304        let assert_fns: Vec<_> = cap_types
305            .iter()
306            .enumerate()
307            .map(|(i, perm_ty)| {
308                let fn_name = format_ident!("_assert_has_{}", i);
309                quote! {
310                    fn #fn_name<T: capsec_core::has::Has<#perm_ty>>() {}
311                }
312            })
313            .collect();
314
315        let assert_calls: Vec<_> = (0..cap_types.len())
316            .map(|i| {
317                let fn_name = format_ident!("_assert_has_{}", i);
318                quote! { #fn_name::<#inner_type>(); }
319            })
320            .collect();
321
322        Some(quote! {
323            const _: () = {
324                #(#assert_fns)*
325                fn _check() {
326                    #(#assert_calls)*
327                }
328            };
329        })
330    } else if !has_impl_bounds && !func.sig.inputs.is_empty() && !cap_types.is_empty() {
331        // Concrete types present but no `on` keyword
332        return Err(syn::Error::new_spanned(
333            &func.sig,
334            "#[capsec::requires] on a function with concrete parameter types requires \
335             `on = <param>` to identify the capability parameter.\n\
336             Example: #[capsec::requires(fs::read, on = ctx)]",
337        ));
338    } else {
339        None
340    };
341
342    let func_vis = &func.vis;
343    let func_sig = &func.sig;
344    let func_block = &func.block;
345    let func_attrs = &func.attrs;
346
347    Ok(quote! {
348        #(#func_attrs)*
349        #[doc = #doc_string]
350        #func_vis #func_sig {
351            #assertion
352            #func_block
353        }
354    })
355}
356
357fn contains_impl_trait(ty: &Type) -> bool {
358    match ty {
359        Type::ImplTrait(_) => true,
360        Type::Reference(r) => contains_impl_trait(&r.elem),
361        Type::Paren(p) => contains_impl_trait(&p.elem),
362        _ => false,
363    }
364}
365
366fn find_param_type(sig: &syn::Signature, name: &syn::Ident) -> syn::Result<Type> {
367    for arg in &sig.inputs {
368        if let FnArg::Typed(pat_type) = arg
369            && let Pat::Ident(pi) = &*pat_type.pat
370            && pi.ident == *name
371        {
372            return Ok((*pat_type.ty).clone());
373        }
374    }
375    Err(syn::Error::new_spanned(
376        name,
377        format!("parameter '{}' not found in function signature", name),
378    ))
379}
380
381fn unwrap_references(ty: &Type) -> &Type {
382    match ty {
383        Type::Reference(r) => unwrap_references(&r.elem),
384        Type::Paren(p) => unwrap_references(&p.elem),
385        _ => ty,
386    }
387}
388
389/// Marks a function as capability-free.
390///
391/// This is a declaration for the `cargo capsec check` lint tool — any ambient
392/// authority call found inside a `#[deny]` function will be flagged as a violation.
393///
394/// The macro itself does not enforce anything at compile time (there's no type-system
395/// mechanism to prevent `std::fs` imports). Enforcement is in the lint tool.
396///
397/// # Usage
398///
399/// ```rust,ignore
400/// // Deny all I/O
401/// #[capsec::deny(all)]
402/// fn pure_transform(input: &[u8]) -> Vec<u8> {
403///     input.iter().map(|b| b.wrapping_add(1)).collect()
404/// }
405///
406/// // Deny only network access
407/// #[capsec::deny(net)]
408/// fn local_only(cap: &impl Has<FsRead>) -> Vec<u8> {
409///     capsec::fs::read("/tmp/data", cap).unwrap()
410/// }
411/// ```
412///
413/// # Supported categories
414///
415/// `all`, `fs`, `net`, `env`, `process`
416#[proc_macro_attribute]
417pub fn deny(attr: TokenStream, item: TokenStream) -> TokenStream {
418    let denied = parse_macro_input!(attr with Punctuated::<Meta, Token![,]>::parse_terminated);
419
420    let item_clone: proc_macro2::TokenStream = item.clone().into();
421    let func = match syn::parse::<ItemFn>(item) {
422        Ok(f) => f,
423        Err(e) => {
424            let err = e.into_compile_error();
425            return quote! { #err #item_clone }.into();
426        }
427    };
428
429    let deny_names: Vec<String> = denied
430        .iter()
431        .map(|meta| {
432            meta.path()
433                .get_ident()
434                .map(|i| i.to_string())
435                .unwrap_or_default()
436        })
437        .collect();
438
439    let doc_string = format!("capsec::deny({})", deny_names.join(", "));
440
441    let func_vis = &func.vis;
442    let func_sig = &func.sig;
443    let func_block = &func.block;
444    let func_attrs = &func.attrs;
445
446    let expanded = quote! {
447        #(#func_attrs)*
448        #[doc = #doc_string]
449        #func_vis #func_sig
450            #func_block
451    };
452
453    expanded.into()
454}
455
456/// Injects `CapRoot` creation into a function entry point.
457///
458/// Removes the first parameter (which must be typed as `CapRoot`) and prepends
459/// `let {param_name} = capsec::root();` to the function body.
460///
461/// # Usage
462///
463/// ```rust,ignore
464/// #[capsec::main]
465/// fn main(root: CapRoot) {
466///     let fs = root.fs_read();
467///     // ...
468/// }
469/// ```
470///
471/// # With `#[tokio::main]`
472///
473/// Place `#[capsec::main]` above `#[tokio::main]`:
474///
475/// ```rust,ignore
476/// #[capsec::main]
477/// #[tokio::main]
478/// async fn main(root: CapRoot) { ... }
479/// ```
480#[proc_macro_attribute]
481pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
482    let func = parse_macro_input!(item as ItemFn);
483
484    match main_inner(&func) {
485        Ok(tokens) => tokens.into(),
486        Err(e) => e.into_compile_error().into(),
487    }
488}
489
490fn main_inner(func: &ItemFn) -> syn::Result<proc_macro2::TokenStream> {
491    if func.sig.inputs.is_empty() {
492        if func.sig.asyncness.is_some() {
493            return Err(syn::Error::new_spanned(
494                &func.sig,
495                "#[capsec::main] found no CapRoot parameter. If combining with #[tokio::main], \
496                 place #[capsec::main] above #[tokio::main]:\n\n  \
497                 #[capsec::main]\n  \
498                 #[tokio::main]\n  \
499                 async fn main(root: CapRoot) { ... }",
500            ));
501        }
502        return Err(syn::Error::new_spanned(
503            &func.sig,
504            "#[capsec::main] expected first parameter of type CapRoot",
505        ));
506    }
507
508    // Extract first parameter
509    let first_arg = &func.sig.inputs[0];
510    let (param_name, param_type) = match first_arg {
511        FnArg::Typed(pat_type) => {
512            let name = if let Pat::Ident(pi) = &*pat_type.pat {
513                pi.ident.clone()
514            } else {
515                return Err(syn::Error::new_spanned(
516                    &pat_type.pat,
517                    "#[capsec::main] expected a simple identifier for the CapRoot parameter",
518                ));
519            };
520            (name, &*pat_type.ty)
521        }
522        FnArg::Receiver(r) => {
523            return Err(syn::Error::new_spanned(
524                r,
525                "#[capsec::main] cannot be used on methods with self",
526            ));
527        }
528    };
529
530    // Validate type is CapRoot
531    let type_str = quote!(#param_type).to_string().replace(' ', "");
532    if type_str != "CapRoot" && type_str != "capsec::CapRoot" {
533        return Err(syn::Error::new_spanned(
534            param_type,
535            "first parameter must be CapRoot",
536        ));
537    }
538
539    // Build new signature without the first parameter
540    let remaining_params: Vec<_> = func.sig.inputs.iter().skip(1).collect();
541    let func_attrs = &func.attrs;
542    let func_vis = &func.vis;
543    let func_name = &func.sig.ident;
544    let func_generics = &func.sig.generics;
545    let func_output = &func.sig.output;
546    let func_asyncness = &func.sig.asyncness;
547    let func_block = &func.block;
548
549    Ok(quote! {
550        #(#func_attrs)*
551        #func_vis #func_asyncness fn #func_name #func_generics(#(#remaining_params),*) #func_output {
552            let #param_name = capsec::root();
553            #func_block
554        }
555    })
556}
557
558/// Transforms a struct with permission-type fields into a capability context.
559///
560/// Generates:
561/// - Field types rewritten from `PermType` to `Cap<PermType>` (or `SendCap<PermType>`)
562/// - A `new(root: &CapRoot) -> Self` constructor
563/// - `impl Has<P>` for each field's permission type
564///
565/// # Usage
566///
567/// ```rust,ignore
568/// #[capsec::context]
569/// struct AppCtx {
570///     fs: FsRead,
571///     net: NetConnect,
572/// }
573///
574/// // Send variant for async/threaded code:
575/// #[capsec::context(send)]
576/// struct AsyncCtx {
577///     fs: FsRead,
578///     net: NetConnect,
579/// }
580/// ```
581#[proc_macro_attribute]
582pub fn context(attr: TokenStream, item: TokenStream) -> TokenStream {
583    let attr2: proc_macro2::TokenStream = attr.into();
584    let input = parse_macro_input!(item as ItemStruct);
585
586    match context_inner(attr2, &input) {
587        Ok(tokens) => tokens.into(),
588        Err(e) => e.into_compile_error().into(),
589    }
590}
591
592fn context_inner(
593    attr: proc_macro2::TokenStream,
594    input: &ItemStruct,
595) -> syn::Result<proc_macro2::TokenStream> {
596    // Parse `send` flag
597    let attr_str = attr.to_string();
598    let is_send = match attr_str.trim() {
599        "" => false,
600        "send" => true,
601        other => {
602            return Err(syn::Error::new_spanned(
603                &attr,
604                format!("unexpected attribute '{}', expected empty or 'send'", other),
605            ));
606        }
607    };
608
609    // Reject generics
610    if !input.generics.params.is_empty() {
611        return Err(syn::Error::new_spanned(
612            &input.generics,
613            "#[capsec::context] does not support generic structs",
614        ));
615    }
616
617    // Get named fields
618    let fields = match &input.fields {
619        syn::Fields::Named(f) => f,
620        _ => {
621            return Err(syn::Error::new_spanned(
622                input,
623                "#[capsec::context] requires a struct with named fields",
624            ));
625        }
626    };
627
628    // Validate fields and collect permission info
629    // Each entry: (field_name, resolved_perm_type_tokens)
630    let mut field_infos: Vec<(syn::Ident, proc_macro2::TokenStream)> = Vec::new();
631    let mut seen_perms: std::collections::HashSet<String> = std::collections::HashSet::new();
632
633    for field in &fields.named {
634        let field_name = field.ident.as_ref().unwrap().clone();
635        let ty = &field.ty;
636
637        // Check for tuple types
638        if let Type::Tuple(_) = ty {
639            return Err(syn::Error::new_spanned(
640                ty,
641                "tuple permission types are not supported in context structs — use separate fields instead",
642            ));
643        }
644
645        // Extract type path
646        let (perm_key, perm_tokens) = match ty {
647            Type::Path(tp) => {
648                if let Some(seg) = tp.path.segments.last() {
649                    let ident_str = seg.ident.to_string();
650                    // Known built-in? Qualify with capsec_core::permission::
651                    if KNOWN_PERMISSIONS.contains(&ident_str.as_str()) {
652                        let ident = &seg.ident;
653                        (ident_str, quote! { capsec_core::permission::#ident })
654                    } else {
655                        // Custom permission — pass through original type path
656                        (ident_str, quote! { #tp })
657                    }
658                } else {
659                    return Err(syn::Error::new_spanned(
660                        ty,
661                        format!("field '{}' has an empty type path", field_name,),
662                    ));
663                }
664            }
665            _ => {
666                return Err(syn::Error::new_spanned(
667                    ty,
668                    format!(
669                        "field '{}' has type '{}', which is not a valid permission type",
670                        field_name,
671                        quote!(#ty),
672                    ),
673                ));
674            }
675        };
676
677        // Check for duplicates
678        if !seen_perms.insert(perm_key.clone()) {
679            return Err(syn::Error::new_spanned(
680                ty,
681                format!(
682                    "duplicate permission type '{}' — each permission can only appear once in a context struct",
683                    perm_key
684                ),
685            ));
686        }
687
688        field_infos.push((field_name, perm_tokens));
689    }
690
691    let struct_name = &input.ident;
692    let struct_vis = &input.vis;
693    let struct_attrs = &input.attrs;
694
695    // Generate struct fields with rewritten types
696    let struct_fields: Vec<_> = field_infos
697        .iter()
698        .map(|(name, perm)| {
699            if is_send {
700                quote! { #name: capsec_core::cap::SendCap<#perm> }
701            } else {
702                quote! { #name: capsec_core::cap::Cap<#perm> }
703            }
704        })
705        .collect();
706
707    // Generate constructor fields
708    let constructor_fields: Vec<_> = field_infos
709        .iter()
710        .map(|(name, perm)| {
711            if is_send {
712                quote! { #name: root.grant::<#perm>().make_send() }
713            } else {
714                quote! { #name: root.grant::<#perm>() }
715            }
716        })
717        .collect();
718
719    // Generate Has<P> impls
720    let has_impls: Vec<_> = field_infos
721        .iter()
722        .map(|(name, perm)| {
723            quote! {
724                impl capsec_core::has::Has<#perm> for #struct_name {
725                    fn cap_ref(&self) -> capsec_core::cap::Cap<#perm> {
726                        self.#name.cap_ref()
727                    }
728                }
729            }
730        })
731        .collect();
732
733    Ok(quote! {
734        #(#struct_attrs)*
735        #struct_vis struct #struct_name {
736            #(#struct_fields,)*
737        }
738
739        impl #struct_name {
740            /// Creates a new context by granting all capabilities from the root.
741            pub fn new(root: &capsec_core::root::CapRoot) -> Self {
742                Self {
743                    #(#constructor_fields,)*
744                }
745            }
746        }
747
748        #(#has_impls)*
749    })
750}