extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, LitInt, Type};
fn get_buffer_cap(input: &DeriveInput) -> LitInt {
let default_size = 32;
let mut buffer_cap_val = None;
for attr in &input.attrs {
if attr.path().is_ident("bus_ctl") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("buffer_cap") {
let content = meta.value()?.parse::<LitInt>()?;
buffer_cap_val = Some(content);
return Ok(());
}
Err(meta.error("unsupported `bus_ctl` property"))
})
.ok();
}
}
buffer_cap_val
.unwrap_or_else(|| LitInt::new(&default_size.to_string(), proc_macro2::Span::call_site()))
}
#[proc_macro_derive(BusLocal, attributes(bus_ctl))]
pub fn bus_local_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let buffer_cap = get_buffer_cap(&input);
let expanded = if input.generics.params.is_empty() {
quote! {
impl #impl_generics pipeworks_core::reg::BusType for #name #ty_generics #where_clause {
fn get_type_reg() -> pipeworks_core::reg::TypeReg {
pipeworks_core::reg::TypeReg {
type_name: std::any::type_name::<Self>(),
type_id: std::any::TypeId::of::<Self>(),
buffer_cap: #buffer_cap,
bitcode_support: None,
}
}
}
pipeworks_core::inventory::submit! {
use pipeworks_core::reg::BusType;
pipeworks_core::reg::TypeRegFn(#name #ty_generics ::get_type_reg)
}
}
} else {
quote! {
impl #impl_generics pipeworks_core::reg::BusType for #name #ty_generics #where_clause {
fn get_type_reg() -> pipeworks_core::reg::TypeReg {
pipeworks_core::reg::TypeReg {
type_name: std::any::type_name::<Self>(),
type_id: std::any::TypeId::of::<Self>(),
buffer_cap: #buffer_cap,
bitcode_support: None,
}
}
}
}
};
expanded.into()
}
#[proc_macro_derive(BusShared, attributes(bus_ctl))]
pub fn bus_shared_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let buffer_cap = get_buffer_cap(&input);
let expanded = if input.generics.params.is_empty() {
quote! {
impl #impl_generics pipeworks_core::reg::BusType for #name #ty_generics #where_clause {
fn get_type_reg() -> pipeworks_core::reg::TypeReg {
use std::{sync::Arc, any::{Any, type_name, TypeId}};
fn to_bytes(type_erased: Arc<Box<dyn Any + Send + Sync + 'static>>) -> Vec<u8> {
let value = type_erased.downcast_ref::<#name #ty_generics>().unwrap();
bitcode::encode(value)
}
fn from_bytes(
bytes: &[u8],
) -> Result<Arc<Box<dyn Any + Send + Sync + 'static>>, bitcode::Error> {
let value = bitcode::decode::<#name #ty_generics>(bytes)?;
Ok(Arc::new(Box::new(value)))
}
pipeworks_core::reg::TypeReg {
type_name: type_name::<Self>(),
type_id: TypeId::of::<Self>(),
buffer_cap: #buffer_cap,
bitcode_support: Some((to_bytes, from_bytes)),
}
}
}
pipeworks_core::inventory::submit! {
use pipeworks_core::reg::BusType;
pipeworks_core::reg::TypeRegFn(#name #ty_generics ::get_type_reg)
}
}
} else {
quote! {
impl #impl_generics pipeworks_core::reg::BusType for #name #ty_generics #where_clause {
fn get_type_reg() -> pipeworks_core::reg::TypeReg {
use std::{sync::Arc, any::{Any, type_name, TypeId}};
fn to_bytes(type_erased: Arc<Box<dyn Any + Send + Sync + 'static>>) -> Vec<u8> {
let value = type_erased.downcast_ref::<#name #ty_generics>().unwrap();
bitcode::encode(value)
}
fn from_bytes(
bytes: &[u8],
) -> Result<Arc<Box<dyn Any + Send + Sync + 'static>>, bitcode::Error> {
let value = bitcode::decode::<#name #ty_generics>(bytes)?;
Ok(Arc::new(Box::new(value)))
}
pipeworks_core::reg::TypeReg {
type_name: type_name::<Self>(),
type_id: TypeId::of::<Self>(),
buffer_cap: #buffer_cap,
bitcode_support: Some((to_bytes, from_bytes)),
}
}
}
}
};
expanded.into()
}
#[proc_macro]
pub fn register_generic(input: TokenStream) -> TokenStream {
let ty = parse_macro_input!(input as Type);
let expanded = quote! {
use pipeworks_core::reg::BusType;
pipeworks_core::inventory::submit! {
pipeworks_core::reg::TypeRegFn(#ty ::get_type_reg)
}
};
expanded.into()
}