From 13d060776fa8f06f4649bbe2d11ca0c48ba1b3df Mon Sep 17 00:00:00 2001 From: Albin Chaboissier Date: Wed, 11 Mar 2026 18:40:58 +0100 Subject: [PATCH] Blocks and flowgraph --- oxydsp-flowgraph-macros/Cargo.toml | 12 +++ oxydsp-flowgraph-macros/src/lib.rs | 124 +++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 oxydsp-flowgraph-macros/Cargo.toml create mode 100644 oxydsp-flowgraph-macros/src/lib.rs diff --git a/oxydsp-flowgraph-macros/Cargo.toml b/oxydsp-flowgraph-macros/Cargo.toml new file mode 100644 index 0000000..3b618b7 --- /dev/null +++ b/oxydsp-flowgraph-macros/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "oxydsp-flowgraph-macros" +version = "0.1.0" +edition = "2024" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.106" +quote = "1.0.45" +syn = "2.0.117" diff --git a/oxydsp-flowgraph-macros/src/lib.rs b/oxydsp-flowgraph-macros/src/lib.rs new file mode 100644 index 0000000..46ba18c --- /dev/null +++ b/oxydsp-flowgraph-macros/src/lib.rs @@ -0,0 +1,124 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{DeriveInput, Fields, Ident, parse_macro_input}; + +#[proc_macro_derive(BlockIO, attributes(input, output))] +pub fn derive_block_io(item: TokenStream) -> TokenStream +{ + let input = parse_macro_input!(item as DeriveInput); + let inputs; + let outputs; + match input.data + { + syn::Data::Struct(data_struct) => + { + inputs = derive_block_get_marked_idents(&data_struct.fields, "input"); + outputs = derive_block_get_marked_idents(&data_struct.fields, "output"); + } + 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) -> proc_macro2::TokenStream +{ + quote! { + fn get_successors(&self) -> Vec + { + let mut successors = Vec::new(); + #( + if let Some(next) = self.#outputs.get_consumer_block() + { + successors.push(next); + } + )* + successors + } + } +} + +fn derive_block_io_count(inputs: &Vec, outputs: &Vec) -> proc_macro2::TokenStream +{ + let input_count = inputs.len(); + let output_count = outputs.len(); + quote! { + fn input_count(&self) -> usize + { + #input_count + } + + fn output_count(&self) -> usize + { + #output_count + } + } +} + +fn derive_block_set_index(inputs: &Vec, outputs: &Vec) -> 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>( + fields: &Fields, + required_attribute: S, +) -> Vec +{ + 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 +}