pipeworks_derive/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, DeriveInput, LitInt, Type};
6
7fn get_buffer_cap(input: &DeriveInput) -> LitInt {
8    let default_size = 32;
9    let mut buffer_cap_val = None;
10
11    for attr in &input.attrs {
12        if attr.path().is_ident("bus_ctl") {
13            attr.parse_nested_meta(|meta| {
14                if meta.path.is_ident("buffer_cap") {
15                    let content = meta.value()?.parse::<LitInt>()?;
16                    buffer_cap_val = Some(content);
17                    return Ok(());
18                }
19                Err(meta.error("unsupported `bus_ctl` property"))
20            })
21            .ok();
22        }
23    }
24
25    // Return the parsed buffer size or the default
26    buffer_cap_val
27        .unwrap_or_else(|| LitInt::new(&default_size.to_string(), proc_macro2::Span::call_site()))
28}
29
30#[proc_macro_derive(BusLocal, attributes(bus_ctl))]
31pub fn bus_local_derive(input: TokenStream) -> TokenStream {
32    let input = parse_macro_input!(input as DeriveInput);
33    let name = &input.ident;
34    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
35    let buffer_cap = get_buffer_cap(&input);
36
37    let expanded = if input.generics.params.is_empty() {
38        quote! {
39            impl #impl_generics pipeworks_core::reg::BusType for #name #ty_generics #where_clause {
40                fn get_type_reg() -> pipeworks_core::reg::TypeReg {
41                    pipeworks_core::reg::TypeReg {
42                        type_name: std::any::type_name::<Self>(),
43                        type_id: std::any::TypeId::of::<Self>(),
44                        buffer_cap: #buffer_cap,
45                        bitcode_support: None,
46                    }
47                }
48            }
49
50            pipeworks_core::inventory::submit! {
51                use pipeworks_core::reg::BusType;
52                pipeworks_core::reg::TypeRegFn(#name #ty_generics ::get_type_reg)
53            }
54        }
55    } else {
56        quote! {
57            impl #impl_generics pipeworks_core::reg::BusType for #name #ty_generics #where_clause {
58                fn get_type_reg() -> pipeworks_core::reg::TypeReg {
59                    pipeworks_core::reg::TypeReg {
60                        type_name: std::any::type_name::<Self>(),
61                        type_id: std::any::TypeId::of::<Self>(),
62                        buffer_cap: #buffer_cap,
63                        bitcode_support: None,
64                    }
65                }
66            }
67        }
68    };
69
70    expanded.into()
71}
72
73#[proc_macro_derive(BusShared, attributes(bus_ctl))]
74pub fn bus_shared_derive(input: TokenStream) -> TokenStream {
75    let input = parse_macro_input!(input as DeriveInput);
76    let name = &input.ident;
77    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
78    let buffer_cap = get_buffer_cap(&input);
79
80    let expanded = if input.generics.params.is_empty() {
81        quote! {
82            impl #impl_generics pipeworks_core::reg::BusType for #name #ty_generics #where_clause {
83                fn get_type_reg() -> pipeworks_core::reg::TypeReg {
84                    use std::{sync::Arc, any::{Any, type_name, TypeId}};
85
86                    fn to_bytes(type_erased: Arc<Box<dyn Any + Send + Sync + 'static>>) -> Vec<u8> {
87                        let value = type_erased.downcast_ref::<#name #ty_generics>().unwrap();
88                        bitcode::encode(value)
89                    }
90
91                    fn from_bytes(
92                        bytes: &[u8],
93                    ) -> Result<Arc<Box<dyn Any + Send + Sync + 'static>>, bitcode::Error> {
94                        let value = bitcode::decode::<#name #ty_generics>(bytes)?;
95                        Ok(Arc::new(Box::new(value)))
96                    }
97
98                    pipeworks_core::reg::TypeReg {
99                        type_name:  type_name::<Self>(),
100                        type_id: TypeId::of::<Self>(),
101                        buffer_cap: #buffer_cap,
102                        bitcode_support: Some((to_bytes, from_bytes)),
103                    }
104                }
105            }
106
107            pipeworks_core::inventory::submit! {
108                use pipeworks_core::reg::BusType;
109                pipeworks_core::reg::TypeRegFn(#name #ty_generics ::get_type_reg)
110            }
111        }
112    } else {
113        quote! {
114            impl #impl_generics pipeworks_core::reg::BusType for #name #ty_generics #where_clause {
115                fn get_type_reg() -> pipeworks_core::reg::TypeReg {
116                    use std::{sync::Arc, any::{Any, type_name, TypeId}};
117
118                    fn to_bytes(type_erased: Arc<Box<dyn Any + Send + Sync + 'static>>) -> Vec<u8> {
119                        let value = type_erased.downcast_ref::<#name #ty_generics>().unwrap();
120                        bitcode::encode(value)
121                    }
122
123                    fn from_bytes(
124                        bytes: &[u8],
125                    ) -> Result<Arc<Box<dyn Any + Send + Sync + 'static>>, bitcode::Error> {
126                        let value = bitcode::decode::<#name #ty_generics>(bytes)?;
127                        Ok(Arc::new(Box::new(value)))
128                    }
129
130                    pipeworks_core::reg::TypeReg {
131                        type_name: type_name::<Self>(),
132                        type_id: TypeId::of::<Self>(),
133                        buffer_cap: #buffer_cap,
134                        bitcode_support: Some((to_bytes, from_bytes)),
135                    }
136                }
137            }
138        }
139    };
140
141    expanded.into()
142}
143
144#[proc_macro]
145pub fn register_generic(input: TokenStream) -> TokenStream {
146    let ty = parse_macro_input!(input as Type);
147
148    let expanded = quote! {
149        use pipeworks_core::reg::BusType;
150        pipeworks_core::inventory::submit! {
151            pipeworks_core::reg::TypeRegFn(#ty ::get_type_reg)
152        }
153    };
154
155    expanded.into()
156}