1use proc_macro::TokenStream;
2use quote::quote;
3
4struct SplitOutputs {
5 output: syn::Expr,
6 count: syn::LitInt,
7}
8
9impl syn::parse::Parse for SplitOutputs {
10 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
11 let output = input.parse()?;
12 input.parse::<syn::Token![,]>()?;
13 let count = input.parse()?;
14 Ok(Self { output, count })
15 }
16}
17
18#[proc_macro]
19pub fn split_outputs(input: TokenStream) -> TokenStream {
20 let input = syn::parse_macro_input!(input as SplitOutputs);
21
22 let output = input.output;
23
24 let count = input.count.base10_parse().unwrap();
25
26 let mut idents = vec![];
27 for i in 0..count {
28 let ident = syn::Ident::new(&format!("out{}", i), proc_macro2::Span::call_site());
29 idents.push(ident);
30 }
31
32 let start = quote! {
33 let raug::processor::ProcessorOutputs {
34 output_spec,
35 outputs,
36 mode,
37 } = #output;
38
39 let [#(#idents),*] = outputs else {
40 panic!("Expected {} outputs, got {}", #count, outputs.len());
41 };
42 };
43
44 let mut chunks = vec![];
45
46 for (i, ident) in idents.iter().enumerate() {
47 let chunk = quote! {
48 raug::processor::ProcessorOutputs::new(
49 std::slice::from_ref(&output_spec[#i]),
50 std::slice::from_mut(#ident),
51 mode,
52 )
53 };
54 chunks.push(chunk);
55 }
56
57 let output = quote! {{
58 #start
59
60 (#(#chunks),*)
61 }};
62
63 output.into()
64}
65
66struct IterProcIoAs {
67 inputs: syn::Ident,
68 input_types: syn::punctuated::Punctuated<syn::Type, syn::Token![,]>,
69 outputs: syn::Ident,
70 output_types: syn::punctuated::Punctuated<syn::Type, syn::Token![,]>,
71}
72
73impl syn::parse::Parse for IterProcIoAs {
74 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
75 let inputs = input.parse()?;
76 input.parse::<syn::Token![as]>()?;
77 let input_types;
78 syn::bracketed!(input_types in input);
79 let input_types = input_types.parse_terminated(syn::Type::parse, syn::Token![,])?;
80 input.parse::<syn::Token![,]>()?;
81 let outputs = input.parse()?;
82 input.parse::<syn::Token![as]>()?;
83 let output_types;
84 syn::bracketed!(output_types in input);
85 let output_types = output_types.parse_terminated(syn::Type::parse, syn::Token![,])?;
86 Ok(Self {
87 inputs,
88 outputs,
89 input_types,
90 output_types,
91 })
92 }
93}
94
95#[proc_macro]
96pub fn iter_proc_io_as(input: TokenStream) -> TokenStream {
97 let input = syn::parse_macro_input!(input as IterProcIoAs);
98
99 let inputs = input.inputs;
100 let outputs = input.outputs;
101
102 let input_count = input.input_types.len();
103 let output_count = input.output_types.len();
104
105 let mut input_idents = vec![];
106 for i in 0..input_count {
107 let ident = syn::Ident::new(&format!("in{}", i), proc_macro2::Span::call_site());
108 input_idents.push(ident);
109 }
110
111 let mut output_idents = vec![];
112 for i in 0..output_count {
113 let ident = syn::Ident::new(&format!("out{}", i), proc_macro2::Span::call_site());
114 output_idents.push(ident);
115 }
116
117 let start = quote! {
118 let raug::processor::ProcessorInputs {
119 input_specs,
120 inputs,
121 mode,
122 sample_rate,
123 block_size,
124 } = #inputs;
125
126 let [#(#input_idents),*] = inputs else {
127 panic!("Expected {} inputs, got {}", #input_count, inputs.len());
128 };
129
130 let raug::processor::ProcessorOutputs {
131 output_spec,
132 outputs,
133 mode,
134 } = #outputs;
135
136 let [#(#output_idents),*] = outputs else {
137 panic!("Expected {} outputs, got {}", #output_count, outputs.len());
138 };
139 };
140
141 let mut chunks = vec![];
142
143 for (i, (input_ident, input_typ)) in input_idents
144 .iter()
145 .zip(input.input_types.iter())
146 .enumerate()
147 {
148 if let syn::Type::Path(path) = input_typ {
149 if path.path.get_ident().unwrap() == "Any" {
150 let chunk = quote! {
151 raug::processor::ProcessorInputs::new(
152 std::slice::from_ref(&input_specs[#i]),
153 std::slice::from_ref(#input_ident),
154 mode,
155 sample_rate,
156 block_size,
157 ).iter_input(0)
158 };
159 chunks.push(chunk);
160 continue;
161 }
162 }
163 let chunk = quote! {
164 raug::processor::ProcessorInputs::new(
165 std::slice::from_ref(&input_specs[#i]),
166 std::slice::from_ref(#input_ident),
167 mode,
168 sample_rate,
169 block_size,
170 ).iter_input_as::<#input_typ>(0)?
171 };
172 chunks.push(chunk);
173 }
174
175 for (i, (output_ident, output_typ)) in output_idents
176 .iter()
177 .zip(input.output_types.iter())
178 .enumerate()
179 {
180 if let syn::Type::Path(path) = output_typ {
181 if path.path.get_ident().unwrap() == "Any" {
182 let chunk = quote! {
183 raug::processor::ProcessorOutputs::new(
184 std::slice::from_ref(&output_spec[#i]),
185 std::slice::from_mut(#output_ident),
186 mode,
187 ).iter_output_mut(0)
188 };
189 chunks.push(chunk);
190 continue;
191 }
192 }
193 let chunk = quote! {
194 raug::processor::ProcessorOutputs::new(
195 std::slice::from_ref(&output_spec[#i]),
196 std::slice::from_mut(#output_ident),
197 mode,
198 ).iter_output_mut_as::<#output_typ>(0)?
199 };
200 chunks.push(chunk);
201 }
202
203 let output = quote! {{
204 #start
205
206 raug::__itertools::izip!(#(#chunks),*)
207 }};
208
209 output.into()
210}