Zyn
This commit is contained in:
@ -7,6 +7,4 @@ edition = "2024"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.106"
|
||||
quote = "1.0.45"
|
||||
syn = "2.0.117"
|
||||
zyn = {version = "0.4.2", features = ["ext"]}
|
||||
|
||||
@ -1,124 +1,84 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{DeriveInput, Fields, Ident, parse_macro_input};
|
||||
use zyn::ext::AttrExt;
|
||||
use zyn::ext::FieldsExt;
|
||||
|
||||
#[proc_macro_derive(BlockIO, attributes(input, output))]
|
||||
pub fn derive_block_io(item: TokenStream) -> TokenStream
|
||||
#[zyn::derive("BlockIO", attributes(input, output))]
|
||||
pub fn block_io(
|
||||
#[zyn(input)] ident: zyn::Extract<zyn::syn::Ident>,
|
||||
#[zyn(input)] generics: zyn::Extract<zyn::syn::Generics>,
|
||||
#[zyn(input)] fields: zyn::Fields,
|
||||
) -> zyn::TokenStream
|
||||
{
|
||||
let input = parse_macro_input!(item as DeriveInput);
|
||||
let inputs;
|
||||
let outputs;
|
||||
match input.data
|
||||
{
|
||||
syn::Data::Struct(data_struct) =>
|
||||
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
|
||||
zyn::zyn!(
|
||||
impl {{impl_generics}} oxydsp_flowgraph::block::BlockIO for {{ ident.inner() }} {{ type_generics }}
|
||||
where {{ where_clause }}
|
||||
{
|
||||
inputs = derive_block_get_marked_idents(&data_struct.fields, "input");
|
||||
outputs = derive_block_get_marked_idents(&data_struct.fields, "output");
|
||||
@block_io_set_index(fields = fields.clone())
|
||||
@block_io_get_successors(fields = fields.clone())
|
||||
@block_io_counts(fields = fields.clone())
|
||||
}
|
||||
syn::Data::Enum(_) | syn::Data::Union(_) => unimplemented!("Enum/Unions not supported"),
|
||||
}
|
||||
|
||||
let struct_name = input.ident;
|
||||
let func_set_index = derive_block_set_index(&inputs, &outputs);
|
||||
let func_get_successors = derive_block_get_successors(&outputs);
|
||||
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
quote! {
|
||||
impl #impl_generics oxydsp_flowgraph::block::BlockIO for #struct_name #type_generics
|
||||
#where_clause
|
||||
{
|
||||
#func_set_index
|
||||
|
||||
#func_get_successors
|
||||
}
|
||||
}
|
||||
.into()
|
||||
)
|
||||
}
|
||||
|
||||
fn derive_block_get_successors(outputs: &Vec<Ident>) -> proc_macro2::TokenStream
|
||||
#[zyn::element]
|
||||
fn block_io_set_index(fields: zyn::syn::Fields) -> zyn::TokenStream
|
||||
{
|
||||
quote! {
|
||||
fn get_successors(&self) -> Vec<oxydsp_flowgraph::edge::BlockIOIndex>
|
||||
let fields = fields.as_named().unwrap().named.clone();
|
||||
zyn::zyn!(
|
||||
fn set_index(&self, block_index: usize)
|
||||
{
|
||||
let mut successors = Vec::new();
|
||||
#(
|
||||
if let Some(next) = self.#outputs.get_consumer_block()
|
||||
{
|
||||
successors.push(next);
|
||||
}
|
||||
)*
|
||||
successors
|
||||
use oxydsp_flowgraph::edge::BlockIOIndex;
|
||||
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("input"))).enumerate())
|
||||
{
|
||||
self.{{field.1.ident}}.set_block_index(BlockIOIndex {block_index, port_index: {{ field.0 }} });
|
||||
}
|
||||
|
||||
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("output"))).enumerate())
|
||||
{
|
||||
self.{{field.1.ident}}.set_block_index(BlockIOIndex {block_index, port_index: {{ field.0 }} });
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn derive_block_io_count(inputs: &Vec<Ident>, outputs: &Vec<Ident>) -> proc_macro2::TokenStream
|
||||
#[zyn::element]
|
||||
fn block_io_get_successors(fields: zyn::syn::Fields) -> zyn::TokenStream
|
||||
{
|
||||
let input_count = inputs.len();
|
||||
let output_count = outputs.len();
|
||||
quote! {
|
||||
let fields = fields.as_named().unwrap().named.clone();
|
||||
zyn::zyn!(
|
||||
fn get_successors(&self, block_index: usize) -> Vec<oxydsp_flowgraph::edge::BlockIOIndex>
|
||||
{
|
||||
let mut output = vec![];
|
||||
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("output"))).enumerate())
|
||||
{
|
||||
output.push(self.{{ field.1.ident }}.get_consumer_block());
|
||||
}
|
||||
output
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[zyn::element]
|
||||
fn block_io_counts(fields: zyn::syn::Fields) -> zyn::TokenStream
|
||||
{
|
||||
let fields = fields.as_named().unwrap().named.clone();
|
||||
let input_count = fields
|
||||
.iter()
|
||||
.filter(|x| x.attrs.iter().any(|x| x.is("input")))
|
||||
.count();
|
||||
let output_count = fields
|
||||
.iter()
|
||||
.filter(|x| x.attrs.iter().any(|x| x.is("output")))
|
||||
.count();
|
||||
zyn::zyn!(
|
||||
fn input_count(&self) -> usize
|
||||
{
|
||||
#input_count
|
||||
return { { input_count } };
|
||||
}
|
||||
|
||||
fn output_count(&self) -> usize
|
||||
{
|
||||
#output_count
|
||||
return { { output_count } };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_block_set_index(inputs: &Vec<Ident>, outputs: &Vec<Ident>) -> proc_macro2::TokenStream
|
||||
{
|
||||
quote! {
|
||||
fn set_index(&self, block_index: usize)
|
||||
{
|
||||
use oxydsp_flowgraph::edge::BlockIOIndex;
|
||||
let mut counter = 0;
|
||||
#(
|
||||
self.#inputs.set_block_index(
|
||||
BlockIOIndex
|
||||
{
|
||||
block_index,
|
||||
port_index: counter,
|
||||
}
|
||||
);
|
||||
counter += 1;
|
||||
)*
|
||||
counter = 0;
|
||||
#(
|
||||
self.#outputs.set_block_index(
|
||||
BlockIOIndex
|
||||
{
|
||||
block_index,
|
||||
port_index: counter,
|
||||
}
|
||||
);
|
||||
counter += 1;
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn derive_block_get_marked_idents<S: AsRef<str>>(
|
||||
fields: &Fields,
|
||||
required_attribute: S,
|
||||
) -> Vec<Ident>
|
||||
{
|
||||
let mut idents = vec![];
|
||||
for field in fields
|
||||
{
|
||||
'inner: for attribute in field.attrs.iter()
|
||||
{
|
||||
if let Some(name) = attribute.meta.path().segments.first()
|
||||
&& name.ident == required_attribute.as_ref()
|
||||
{
|
||||
idents.push(field.ident.clone().unwrap());
|
||||
break 'inner;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idents
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user