Adding sync block macro

This commit is contained in:
2026-03-12 15:24:03 +01:00
parent 008a765fe3
commit e13b4a49b5
7 changed files with 320 additions and 25 deletions

View File

@ -7,4 +7,4 @@ edition = "2024"
proc-macro = true
[dependencies]
zyn = {version = "0.4.2", features = ["ext"]}
zyn = {version = "0.5", features = ["ext", "pretty"]}

View File

@ -1,5 +1,11 @@
use core::panic;
use proc_macro::Ident;
use proc_macro::Spacing;
use zyn::ToTokens;
use zyn::ext::AttrExt;
use zyn::ext::FieldsExt;
use zyn::syn::spanned::Spanned;
#[zyn::derive("BlockIO", attributes(input, output))]
pub fn block_io(
@ -16,6 +22,8 @@ pub fn block_io(
@block_io_set_index(fields = fields.clone())
@block_io_get_successors(fields = fields.clone())
@block_io_counts(fields = fields.clone())
@block_io_set_streams(fields = fields.clone())
@block_io_create_stream(fields = fields.clone())
}
)
}
@ -46,12 +54,15 @@ fn block_io_get_successors(fields: zyn::syn::Fields) -> zyn::TokenStream
{
let fields = fields.as_named().unwrap().named.clone();
zyn::zyn!(
fn get_successors(&self, block_index: usize) -> Vec<oxydsp_flowgraph::edge::BlockIOIndex>
fn get_successors(&self) -> 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());
if let Some(block_index) = self.{{ field.1.ident }}.get_consumer_block()
{
output.push(block_index);
}
}
output
}
@ -82,3 +93,132 @@ fn block_io_counts(fields: zyn::syn::Fields) -> zyn::TokenStream
}
)
}
#[zyn::element]
fn block_io_set_streams(fields: zyn::syn::Fields) -> zyn::TokenStream
{
zyn::zyn!(
fn set_anonymous_out_stream(
&mut self,
output_index: usize,
producer: oxydsp_flowgraph::edge::AnonymousStreamProducer,
)
{
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("output"))).enumerate())
{
self.{{field.1.ident}}.set_anonymous_stream(producer);
}
}
fn set_anonymous_in_stream(&mut self, input_index: usize, consumer: oxydsp_flowgraph::edge::AnonymousStreamConsumer)
{
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("input"))).enumerate())
{
self.{{field.1.ident}}.set_anonymous_stream(consumer);
}
}
)
}
#[zyn::element]
fn block_io_create_stream(fields: zyn::syn::Fields) -> zyn::TokenStream
{
zyn::zyn!(
fn create_anonymous_stream_for(
&mut self,
output_index: usize,
capacity: usize
) -> (oxydsp_flowgraph::edge::AnonymousStreamProducer, oxydsp_flowgraph::edge::AnonymousStreamConsumer)
{
let (tx, rx) = match output_index
{
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("output"))).enumerate())
{
{{ field.0 }} => oxydsp_flowgraph::stream::bounded_queue::<@out_inner_type(ty = field.1.ty.clone())>(capacity),
}
_ => panic!("output_index out of bounds.")
};
(tx.into(), rx.into())
}
)
}
#[zyn::element]
fn out_inner_type(ty: zyn::syn::Type) -> zyn::TokenStream
{
let out_ty = match ty
{
zyn::syn::Type::Path(type_path) => match &type_path.path.segments.last().unwrap().arguments
{
zyn::syn::PathArguments::AngleBracketed(args) => match args.args.first().unwrap()
{
zyn::syn::GenericArgument::Type(x) => Some(x.clone().to_token_stream()),
_ => None,
},
_ => None,
},
_ => None,
};
if out_ty.is_none()
{
bail!("Output type must be a Out<T> type."; span = ty.span());
}
out_ty.unwrap()
}
// Sync block
#[zyn::attribute]
pub fn sync_block(#[zyn(input)] item: zyn::syn::ItemStruct) -> zyn::TokenStream
{
let strcut_item = item.clone();
let (impl_generics, type_generics, where_clause) = item.generics.split_for_impl();
let fields = &item.fields.as_named().unwrap().named;
zyn::zyn!(
{{ strcut_item }}
impl {{ impl_generics }} oxydsp_flowgraph::block::Block for {{ strcut_item.ident }} {{ type_generics }}
where {{ where_clause }}
{
fn work(&mut self) -> oxydsp_flowgraph::block::BlockResult
{
let mut len = usize::MAX;
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("input"))).enumerate())
{
let mut {{ field.1.ident.clone().unwrap() | ident:"{}_reader" }} = self.{{field.1.ident}}.read();
len = len.min({{ field.1.ident.clone().unwrap() | ident:"{}_reader" }}.len());
}
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("output"))).enumerate())
{
let mut {{ field.1.ident.clone().unwrap() | ident: "{}_writer" }} = self.{{field.1.ident}}.write();
len = len.min({{ field.1.ident.clone().unwrap() | ident: "{}_writer" }}.len());
}
for _ in 0..len
{
let (
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("output"))).enumerate())
{
{{ field.1.ident.clone().unwrap() | ident: "{}_out" }},
}
) = self.sync_work((
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("input"))).enumerate())
{
{{ field.1.ident.clone().unwrap() | ident: "{}_reader" }}.pop().unwrap(),
}
));
@for (field in fields.iter().filter(|x| x.attrs.iter().any(|x| x.is("output"))).enumerate())
{
{{ field.1.ident.clone().unwrap() | ident: "{}_writer" }}.push({{ field.1.ident.clone().unwrap() | ident: "{}_out" }}).unwrap();
}
}
oxydsp_flowgraph::block::BlockResult::Ok
}
}
)
}