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 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}