Skip to main content

pyro_macro/format/
bridgeable.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{ItemStruct, Path, parse_quote};
4
5use crate::format::BridgeableArgs;
6
7/// Attribute macro that adds rkyv serialization, the `Bridgeable` trait, and
8/// optionally the `Documented` trait for generating a JSON type spec.
9///
10/// # Usage
11///
12/// ```text
13/// #[bridgeable]                                     // bare minimum
14/// #[bridgeable(Document)]                           // + Documented impl
15/// #[bridgeable(derive(Debug, PartialEq))]           // + archived derives
16/// #[bridgeable(derive(Debug, PartialEq), Document)] // all of the above
17/// ```
18pub fn bridgeable(
19    args: &BridgeableArgs,
20    item: &mut ItemStruct,
21    import_location: &Path,
22) -> syn::Result<TokenStream> {
23    let BridgeableArgs {
24        derives_to_pass,
25        compares_to_add,
26        ..
27    } = args;
28
29    let mut rkyv_pass = Vec::with_capacity(5);
30    rkyv_pass.push(quote!(crate = #import_location::format::rkyv_8::rkyv));
31    if !derives_to_pass.is_empty() {
32        rkyv_pass.push(quote! { attr(derive(#(#derives_to_pass),*)) });
33    };
34
35    if !compares_to_add.is_empty() {
36        rkyv_pass.push(quote! { compare(#(#compares_to_add),*) });
37    };
38
39    item.attrs.push(parse_quote!(#[derive(#import_location::format::rkyv_8::rkyv::Archive, #import_location::format::rkyv_8::rkyv::Serialize, #import_location::format::rkyv_8::rkyv::Deserialize)]));
40    item.attrs.push(parse_quote!(#[rkyv(#(#rkyv_pass),*)]));
41
42    let (name, impl_generics, ty_generics, where_clause) = (
43        &item.ident,
44        item.generics.split_for_impl().0,
45        item.generics.split_for_impl().1,
46        &item.generics.where_clause,
47    );
48
49    // 3. Generate UserHeaderValues + Bridgeable impls (matching common.rs)
50    let bridgeable_block = quote! {
51        impl #impl_generics #import_location::format::Bridgeable for #name #ty_generics #where_clause {
52            type Format = #import_location::format::rkyv_8::Rkyv<#name #ty_generics>;
53        }
54    };
55
56    // 5. Output
57    Ok(quote! {
58        #item
59        #bridgeable_block
60    })
61}