type_flow_macros/lib.rs
1#[allow(unused_imports)]
2use type_flow_traits::{
3 Processor,
4 InPlaceProcessor,
5 TransformProcessor,
6 StatefulProcessor,
7 InPlaceStatefulProcessor,
8 Reverse,
9 ShiftLeft,
10 ShiftRight,
11 SwapStartEnd
12};
13/*macro_rules! count_tts {
14 () => { 0 };
15 ($odd:tt $($a:tt $b:tt)*) => { (count_tts!($($a)*) << 1) | 1 };
16 ($($a:tt $even:tt)*) => { count_tts!($($a)*) << 1 };
17}*/
18
19/// Creates a stateless, data-transforming processor struct.
20///
21/// This macro generates a struct that implements the `Processor<T>` trait,
22/// taking data of a specific type, processing it with a given function,
23/// and returning data of the same type.
24///
25/// # Parameters
26/// - `$struct_name`: The name for the new processor struct.
27/// - `$type`: The type of data the processor will operate on.
28/// - `$process_fn`: A function or closure that takes a value of `$type` and returns a new value of `$type`.
29///
30/// # Examples
31///
32/// ```
33/// use type_flow_macros::processor;
34/// use type_flow_traits::Processor;
35///
36/// fn to_uppercase(s: String) -> String {
37/// s.to_uppercase()
38/// }
39///
40/// processor!(UppercaseProcessor, String, to_uppercase);
41///
42/// let processed = UppercaseProcessor::process("hello".to_string());
43/// assert_eq!(processed, "HELLO");
44/// ```
45#[macro_export]
46macro_rules! processor {
47 ($struct_name:ident, $type:ty, $process_fn:expr) => {
48 pub struct $struct_name;
49 impl Processor<$type> for $struct_name {
50 fn process(data: $type) -> $type {
51 ($process_fn)(data)
52 }
53 }
54 };
55}
56
57/// Creates a stateless pipeline of processors.
58///
59/// This macro generates a struct that chains multiple `Processor` implementations
60/// together into a single pipeline. The data flows through each processor in the
61/// order they are specified.
62///
63/// # Parameters
64/// - `$struct_name`: The name for the new pipeline struct.
65/// - `$type`: The type of data the pipeline will operate on.
66/// - `$($processor: ty),+`: A comma-separated list of processor types that implement `Processor<$type>`.
67///
68/// # Examples
69///
70/// ```
71/// use type_flow_macros::{processor, processor_pipeline};
72/// use type_flow_traits::Processor;
73///
74/// processor!(AddOne, i32, |x| x + 1);
75/// processor!(MulTwo, i32, |x| x * 2);
76///
77/// processor_pipeline!(MyPipeline, i32, AddOne, MulTwo);
78///
79/// let result = MyPipeline::process(10);
80/// assert_eq!(result, 22); // (10 + 1) * 2
81/// ```
82#[macro_export]
83macro_rules! processor_pipeline {
84 ($struct_name:ident, $type:ty, $($processor:ty),+) => {
85 pub struct $struct_name;
86 impl Processor<$type> for $struct_name {
87 fn process(data: $type) -> $type {
88 let result = data;
89 $(
90 let result = <$processor>::process(result);
91 )*
92 result
93 }
94 }
95 }
96}
97
98/// Creates a generic, stateless processor pipeline.
99///
100/// This macro generates a struct that is generic over its processors.
101/// It chains them together, and the pipeline itself implements `Processor`.
102/// This allows for creating flexible pipelines where the exact processors can
103/// be specified at a later time.
104///
105/// # Parameters
106/// - `$struct_name`: The name for the new generic pipeline struct.
107/// - `$processor_type`: The data type the pipeline operates on.
108/// - `$($type_param:ident),+`: A comma-separated list of generic type parameter identifiers.
109/// Each will be constrained to implement `Processor<$processor_type>`.
110///
111/// # Examples
112///
113/// ```
114/// use type_flow_macros::{processor, type_flow_processor_pipeline};
115/// use type_flow_traits::Processor;
116///
117/// processor!(AddTen, i32, |x| x + 10);
118/// processor!(DivTwo, i32, |x| x / 2);
119///
120/// type_flow_processor_pipeline!(GenericPipeline, i32, P1, P2);
121///
122/// let result = GenericPipeline::<AddTen, DivTwo>::process(20);
123/// assert_eq!(result, 15); // (20 + 10) / 2
124/// ```
125#[macro_export]
126macro_rules! type_flow_processor_pipeline {
127 ($struct_name:ident, $processor_type:ty, $($type_param:ident),+) => {
128 pub struct $struct_name<$($type_param: Processor<$processor_type>),*> {
129 _marker: std::marker::PhantomData<($($type_param),*)>,
130 }
131 impl<$($type_param: Processor<$processor_type>),*> Processor<$processor_type> for $struct_name<$($type_param),*> {
132 fn process(data: $processor_type) -> $processor_type{
133 let result = data;
134 $(
135 let result = $type_param::process(result);
136 )*
137 result
138 }
139 }
140 };
141}
142
143/// Creates a stateless, in-place processor that can return an error.
144///
145/// This macro generates a struct that implements the `InPlaceProcessor<T, E>` trait.
146/// It processes data by mutating it directly and can fail with a specified error type.
147///
148/// # Parameters
149/// - `$struct_name`: The name for the new processor struct.
150/// - `$type`: The type of data to be processed (will be passed as `&mut`).
151/// - `$error_type`: The error type for the `Result`.
152/// - `$process_fn`: A function or closure that takes `&mut $type` and returns a `Result<(), $error_type>`.
153///
154/// # Examples
155///
156/// ```
157/// use type_flow_macros::inplace_processor;
158/// use type_flow_traits::InPlaceProcessor;
159///
160/// #[derive(Debug)]
161/// struct MyError;
162///
163/// fn increment(data: &mut i32) -> Result<(), MyError> {
164/// if *data > 100 {
165/// return Err(MyError);
166/// }
167/// *data += 1;
168/// Ok(())
169/// }
170///
171/// inplace_processor!(IncrementProcessor, i32, MyError, increment);
172///
173/// let mut value = 5;
174/// IncrementProcessor::process(&mut value).unwrap();
175/// assert_eq!(value, 6);
176/// ```
177#[macro_export]
178macro_rules! inplace_processor {
179 ($struct_name:ident, $type:ty, $error_type:ty, $process_fn:expr) => {
180 pub struct $struct_name;
181 impl InPlaceProcessor<$type, $error_type> for $struct_name {
182 fn process(data: &mut $type) -> Result<(), $error_type> {
183 ($process_fn)(data)
184 }
185 }
186 };
187}
188
189/// Creates a stateless pipeline of in-place processors.
190///
191/// This macro generates a struct that chains multiple `InPlaceProcessor` implementations.
192/// Data is mutated by each processor in the pipeline sequence. If any processor returns an error,
193/// the pipeline stops and forwards the error.
194///
195/// # Parameters
196/// - `$struct_name`: The name for the new pipeline struct.
197/// - `$type`: The type of data the pipeline will operate on.
198/// - `$error_type`: The common error type for the processors.
199/// - `$($processor: ty),+`: A comma-separated list of types that implement `InPlaceProcessor<$type, $error_type>`.
200///
201/// # Examples
202///
203/// ```
204/// use type_flow_macros::{inplace_processor, inplace_processor_pipeline};
205/// use type_flow_traits::InPlaceProcessor;
206/// #[derive(Debug)]
207/// struct MyError;
208///
209/// inplace_processor!(Add, i32, MyError, |x: &mut i32| { *x += 1; Ok(()) });
210/// inplace_processor!(Mul, i32, MyError, |x: &mut i32| { *x *= 2; Ok(()) });
211///
212/// inplace_processor_pipeline!(MyInPlacePipeline, i32, MyError, Add, Mul);
213///
214/// let mut value = 10;
215/// MyInPlacePipeline::process(&mut value).unwrap();
216/// assert_eq!(value, 22); // (10 + 1) * 2
217/// ```
218#[macro_export]
219macro_rules! inplace_processor_pipeline {
220 ($struct_name:ident, $type:ty, $error_type:ty, $($processor:ty),+) => {
221 pub struct $struct_name;
222 impl InPlaceProcessor<$type, $error_type> for $struct_name {
223 fn process(data: &mut $type) -> Result<(), $error_type> {
224 $(
225 <$processor>::process(data)?;
226 )*
227 Ok(())
228 }
229 }
230 }
231}
232/// Creates a generic, stateless, in-place processor pipeline.
233///
234/// This macro generates a struct that is generic over its `InPlaceProcessor`s.
235/// This allows for creating flexible in-place pipelines where the exact processors can
236/// be specified later.
237///
238/// # Parameters
239/// - `$struct_name`: The name for the new generic pipeline struct.
240/// - `$processor_type`: The data type the pipeline operates on.
241/// - `$processor_error_type`: The common error type.
242/// - `$($type_param:ident),+`: A comma-separated list of generic type parameter identifiers,
243/// each constrained to implement `InPlaceProcessor`.
244///
245/// # Examples
246///
247/// ```
248/// use type_flow_macros::{inplace_processor, type_flow_inplace_processor_pipeline};
249/// use type_flow_traits::InPlaceProcessor;
250/// #[derive(Debug)]
251/// struct MyError;
252///
253/// inplace_processor!(AddTen, i32, MyError, |x: &mut i32| { *x += 10; Ok(()) });
254/// inplace_processor!(DivTwo, i32, MyError, |x: &mut i32| { *x /= 2; Ok(()) });
255///
256/// type_flow_inplace_processor_pipeline!(GenericInPlacePipeline, i32, MyError, P1, P2);
257///
258/// let mut value = 20;
259/// GenericInPlacePipeline::<AddTen, DivTwo>::process(&mut value).unwrap();
260/// assert_eq!(value, 15); // (20 + 10) / 2
261/// ```
262#[macro_export]
263macro_rules! type_flow_inplace_processor_pipeline {
264 ($struct_name:ident, $processor_type:ty, $processor_error_type:ty, $($type_param:ident),+) => {
265 pub struct $struct_name<$($type_param: InPlaceProcessor<$processor_type, $processor_error_type>),*> {
266 _marker: std::marker::PhantomData<($($type_param),*)>,
267 }
268 impl<$($type_param: InPlaceProcessor<$processor_type, $processor_error_type>),*> InPlaceProcessor<$processor_type, $processor_error_type> for $struct_name<$($type_param),*> {
269 fn process(data: &mut $processor_type) -> Result<(), $processor_error_type> {
270 $(
271 $type_param::process(data)?;
272 )*
273 Ok(())
274 }
275 }
276 };
277}
278
279/// Creates a stateless processor that transforms data from an input type to an output type.
280///
281/// This macro generates a struct implementing the `TransformProcessor<I, O>` trait.
282///
283/// # Parameters
284/// - `$struct_name`: The name for the new processor struct.
285/// - `$input_type`: The type of the input data.
286/// - `$output_type`: The type of the output data.
287/// - `$process_fn`: A function or closure that takes `$input_type` and returns `$output_type`.
288///
289/// # Examples
290///
291/// ```
292/// use type_flow_macros::{transform_processor};
293/// use type_flow_traits::TransformProcessor;
294///
295/// // This processor transforms an i32 to a String.
296/// transform_processor!(IntToString, i32, String, |x: i32| x.to_string());
297///
298/// let result = IntToString::process(123);
299/// assert_eq!(result, "123");
300/// ```
301#[macro_export]
302macro_rules! transform_processor {
303 ($struct_name:ident, $input_type:ty, $output_type:ty, $process_fn:expr) => {
304 pub struct $struct_name;
305 impl TransformProcessor<$input_type, $output_type> for $struct_name {
306 fn process(data: $input_type) -> $output_type {
307 ($process_fn)(data)
308 }
309 }
310 };
311}
312
313/// Creates a stateful processor that maintains its own internal state.
314///
315/// This macro generates a struct that implements `StatefulProcessor<T>`. The processing logic
316/// can read and modify the internal state during its operation.
317///
318/// Two variants are available:
319/// 1. Takes a state type and requires the state to be provided via a `new()` constructor.
320/// 2. Takes a state type and an initial value expression, providing a `new()` constructor with no arguments.
321///
322/// # Arms
323///
324/// ## 1. With `new(state)` constructor
325/// - `$struct_name`: Name of the processor struct.
326/// - `$state_type`: Type of the internal state.
327/// - `$type`: Type of the data to be processed.
328/// - `$process_fn`: A closure `|state, data| -> new_data`.
329///
330/// ## 2. With `new()` constructor and initial state
331/// - `$struct_name`: Name of the processor struct.
332/// - `$state_type`: Type of the internal state.
333/// - `$state_value`: An expression that evaluates to the initial state.
334/// - `$type`: Type of the data to be processed.
335/// - `$process_fn`: A closure `|state, data| -> new_data`.
336///
337/// # Examples
338///
339/// ### 1. With `new(state)`
340/// ```
341/// use type_flow_macros::stateful_processor;
342/// use type_flow_traits::StatefulProcessor;
343///
344/// // A processor that adds a configurable number to the input.
345/// stateful_processor!(AddN, i32, i32, |state: &mut i32, data: i32| {
346/// data + *state
347/// });
348///
349/// let mut processor = AddN::new(5); // State is 5
350/// assert_eq!(processor.process(10), 15);
351/// assert_eq!(processor.process(20), 25); // State remains 5
352/// ```
353///
354/// ### 2. With initial state value
355/// ```
356/// use type_flow_macros::stateful_processor;
357/// use type_flow_traits::StatefulProcessor;
358/// // A processor that accumulates values.
359/// stateful_processor!(Accumulator, i32, 0, i32, |state: &mut i32, data: i32| {
360/// *state += data;
361/// *state // returns the new accumulated value
362/// });
363///
364/// let mut processor = Accumulator::new();
365/// assert_eq!(processor.process(5), 5);
366/// assert_eq!(processor.process(10), 15);
367/// assert_eq!(processor.process(-3), 12);
368/// ```
369#[macro_export]
370macro_rules! stateful_processor {
371 // Original version with constructor
372 ($struct_name:ident, $state_type:ty, $type:ty, $process_fn:expr) => {
373 pub struct $struct_name {
374 state: $state_type
375 }
376 impl $struct_name {
377 pub fn new(state: $state_type) -> Self {
378 Self {
379 state
380 }
381 }
382 }
383
384 impl StatefulProcessor<$type> for $struct_name {
385 fn process(&mut self, data: $type) -> $type {
386 let state = &mut self.state;
387 ($process_fn)(state, data)
388 }
389 }
390 };
391
392 // Version with direct state value
393 ($struct_name:ident, $state_type:ty, $state_value:expr, $type:ty, $process_fn:expr) => {
394 pub struct $struct_name {
395 state: $state_type
396 }
397
398 impl $struct_name {
399 pub fn new() -> Self {
400 Self {
401 state: $state_value
402 }
403 }
404 pub fn instance() -> Self {
405 Self::new()
406 }
407 }
408 impl StatefulProcessor<$type> for $struct_name {
409 fn process(&mut self, data: $type) -> $type {
410 let state = &mut self.state;
411 ($process_fn)(state, data)
412 }
413 }
414 };
415}
416
417/// Creates a pipeline of stateful processors.
418///
419/// This macro generates a struct that holds multiple stateful processors and
420/// processes data through them in sequence. Each processor in the pipeline
421/// maintains its own state.
422///
423/// # Arms
424///
425/// ## 1. With named fields for processors
426/// - `$pipeline_name`: Name for the pipeline struct.
427/// - `$data_type`: The type of data the pipeline operates on.
428/// - `$($processor_field:ident: $processor_type:ty),+`: A comma-separated list of `field: Type` pairs for the processors.
429///
430/// ## 2. With auto-generated fields (delegates to a proc-macro)
431/// - `$pipeline_name`: Name for the pipeline struct.
432/// - `$data_type`: The type of data the pipeline operates on.
433/// - `$($processor_type:ty),+`: A comma-separated list of processor types.
434///
435/// # Examples
436///
437/// ```
438/// use type_flow_macros::{stateful_processor, stateful_processor_pipeline};
439/// use type_flow_traits::StatefulProcessor;
440///
441/// // A processor that adds its call count to the data
442/// stateful_processor!(CallCountAdder, i32, 0, i32, |state: &mut i32, data: i32| {
443/// *state += 1;
444/// data + *state
445/// });
446///
447/// // A processor that multiplies data by its call count
448/// stateful_processor!(CallCountMultiplier, i32, 0, i32, |state: &mut i32, data: i32| {
449/// *state += 1;
450/// data * *state
451/// });
452///
453/// // Arm 1: Named fields
454/// stateful_processor_pipeline!(MyStatefulPipeline, i32, adder: CallCountAdder, multiplier: CallCountMultiplier);
455///
456/// let mut pipeline = MyStatefulPipeline::new(CallCountAdder::new(), CallCountMultiplier::new());
457/// // First run: process(10) -> adder(state=1) -> 11 -> multiplier(state=1) -> 11
458/// assert_eq!(pipeline.process(10), 11);
459/// // Second run: process(10) -> adder(state=2) -> 12 -> multiplier(state=2) -> 24
460/// assert_eq!(pipeline.process(10), 24);
461///
462/// // Arm 2: Auto-generated fields
463/// stateful_processor_pipeline!(MyAnonPipeline, i32, CallCountMultiplier, CallCountAdder);
464/// let mut anon_pipeline = MyAnonPipeline::new(CallCountMultiplier::new(), CallCountAdder::new());
465/// assert_eq!(anon_pipeline.process(5), 6); // (5+1)*1
466/// assert_eq!(anon_pipeline.process(5), 12); // (5+2)*2
467/// ```
468#[macro_export]
469macro_rules! stateful_processor_pipeline {
470 ($pipeline_name:ident, $data_type:ty, $($processor_field:ident: $processor_type:ty),+) => {
471 pub struct $pipeline_name {
472 $(
473 $processor_field: $processor_type,
474 )+
475 }
476
477 impl $pipeline_name {
478 pub fn new($($processor_field: $processor_type),+) -> Self {
479 Self {
480 $(
481 $processor_field,
482 )+
483 }
484 }
485 }
486
487 impl StatefulProcessor<$data_type> for $pipeline_name {
488 fn process(&mut self, mut data: $data_type) -> $data_type {
489 $(
490 data = self.$processor_field.process(data);
491 )*
492 data
493 }
494 }
495 };
496
497 ($pipeline_name:ident, $data_type:ty, $($processor_type:ty),+) => {
498 type_flow_proc_macros::stateful_processor_pipeline_with_index!($pipeline_name, $data_type, $($processor_type),+);
499 };
500}
501
502/// Creates a stateful, in-place processor that can return an error.
503///
504/// This macro generates a struct that implements `InPlaceStatefulProcessor<T, E>`,
505/// combining state management with in-place mutation and error handling.
506///
507/// # Arms
508///
509/// ## 1. With `new(state)` constructor
510/// - `$struct_name`: Name of the processor struct.
511/// - `$state_type`: Type of the internal state.
512/// - `$type`: Type of data to process.
513/// - `$error_type`: Error type for the `Result`.
514/// - `$process_fn`: A closure `|state, data| -> Result<(), E>`.
515///
516/// ## 2. With `new()` constructor and initial state
517/// - `$struct_name`: Name of the processor struct.
518/// - `$state_type`: Type of the internal state.
519/// - `$state_value`: An expression for the initial state.
520/// - `$type`: Type of data to process.
521/// - `$error_type`: Error type for the `Result`.
522/// - `$process_fn`: A closure `|state, data| -> Result<(), E>`.
523///
524/// # Examples
525///
526/// ### 1. With `new(state)`
527/// ```
528/// use type_flow_macros::inplace_stateful_processor;
529/// use type_flow_traits::InPlaceStatefulProcessor;
530/// #[derive(Debug)]
531/// struct MyError;
532///
533/// // Adds a configured value, fails if result exceeds a limit from state.
534/// inplace_stateful_processor!(AddNLimited, (i32, i32), i32, MyError, |state: &mut (i32, i32), data: &mut i32| {
535/// *data += state.0;
536/// if *data > state.1 { Err(MyError) } else { Ok(()) }
537/// });
538///
539/// let mut processor = AddNLimited::new((5, 100)); // Add 5, limit 100
540/// let mut value = 10;
541/// processor.process(&mut value).unwrap();
542/// assert_eq!(value, 15);
543/// ```
544///
545/// ### 2. With initial state
546/// ```
547/// use type_flow_macros::inplace_stateful_processor;
548/// use type_flow_traits::InPlaceStatefulProcessor;
549///
550/// // Accumulates values in-place.
551/// inplace_stateful_processor!(Accumulator, i32, 0, i32, (), |state: &mut i32, data: &mut i32| {
552/// *state += *data;
553/// *data = *state;
554/// Ok(())
555/// });
556///
557/// let mut processor = Accumulator::new();
558/// let (mut val1, mut val2) = (5, 10);
559/// processor.process(&mut val1).unwrap();
560/// assert_eq!(val1, 5);
561/// processor.process(&mut val2).unwrap();
562/// assert_eq!(val2, 15); // 5 (previous state) + 10
563/// ```
564#[macro_export]
565macro_rules! inplace_stateful_processor {
566 ($struct_name:ident, $state_type:ty, $type:ty, $error_type:ty, $process_fn:expr) => {
567 pub struct $struct_name {
568 state: $state_type
569 }
570 impl $struct_name {
571 pub fn new(state: $state_type) -> Self {
572 Self {
573 state
574 }
575 }
576 }
577 impl InPlaceStatefulProcessor<$type, $error_type> for $struct_name {
578 fn process(&mut self, data: &mut $type) -> Result<(), $error_type> {
579 let state = &mut self.state;
580 ($process_fn)(state, data)
581 }
582 }
583 };
584 ($struct_name:ident, $state_type:ty, $state_value:expr, $type:ty, $error_type:ty, $process_fn:expr) => {
585 pub struct $struct_name {
586 state: $state_type
587 }
588 impl $struct_name {
589 pub fn new() -> Self {
590 Self {
591 state: $state_value
592 }
593 }
594 pub fn instance() -> Self {
595 Self::new()
596 }
597 }
598 impl InPlaceStatefulProcessor<$type, $error_type> for $struct_name {
599 fn process(&mut self, data: &mut $type) -> Result<(), $error_type> {
600 let state = &mut self.state;
601 ($process_fn)(state, data)
602 }
603 }
604 };
605}
606
607/// Creates a pipeline of stateful, in-place processors.
608///
609/// Generates a struct that holds multiple `InPlaceStatefulProcessor`s and
610/// processes data through them sequentially. Each processor can mutate the data
611/// and its own state. The pipeline stops if any processor returns an error.
612///
613/// # Arms
614///
615/// ## 1. With named fields
616/// - `$pipeline_name`: Name for the pipeline struct.
617/// - `$data_type`: The type of data for the pipeline.
618/// - `$error_type`: The common error type.
619/// - `$($processor_field:ident: $processor_type:ty),+`: A list of `field: Type` pairs.
620///
621/// ## 2. With auto-generated fields (delegates to a proc-macro)
622/// - `$pipeline_name`: Name for the pipeline struct.
623/// - `$data_type`: The type of data for the pipeline.
624/// - `$error_type`: The common error type.
625/// - `$($processor_type:ty),+`: A list of processor types.
626///
627/// # Examples
628///
629/// ```
630/// use type_flow_macros::{inplace_stateful_processor, inplace_stateful_processor_pipeline};
631/// use type_flow_traits::InPlaceStatefulProcessor;
632/// use type_flow_proc_macros::inplace_stateful_processor_pipeline_with_index;
633/// #[derive(Debug)]
634/// struct MyError;
635///
636/// // Processor that adds its call count to data.
637/// inplace_stateful_processor!(CounterAdd, i32, 0, i32, MyError, |state: &mut i32, data: &mut i32| {
638/// *state += 1;
639/// *data += *state;
640/// Ok(())
641/// });
642///
643/// // Processor that multiplies data by its call count.
644/// inplace_stateful_processor!(CounterMul, i32, 0, i32, MyError, |state: &mut i32, data: &mut i32| {
645/// *state += 1;
646/// *data *= *state;
647/// Ok(())
648/// });
649///
650/// // Arm 1: Named fields
651/// inplace_stateful_processor_pipeline!(MyPipeline, i32, MyError, adder: CounterAdd, multiplier: CounterMul);
652///
653/// let mut pipeline = MyPipeline::new(CounterAdd::new(), CounterMul::new());
654/// let mut value = 10;
655///
656/// // First run: value=10 -> adder(s=1) -> 11 -> multiplier(s=1) -> 11
657/// pipeline.process(&mut value).unwrap();
658/// assert_eq!(value, 11);
659///
660/// // Second run: value=11 -> adder(s=2) -> 13 -> multiplier(s=2) -> 26
661/// pipeline.process(&mut value).unwrap();
662/// assert_eq!(value, 26);
663/// ```
664#[macro_export]
665macro_rules! inplace_stateful_processor_pipeline {
666 ($pipeline_name:ident, $data_type:ty, $error_type:ty, $($processor_field:ident: $processor_type:ty),+) => {
667 pub struct $pipeline_name {
668 $(
669 $processor_field: $processor_type,
670 )+
671 }
672 impl $pipeline_name {
673 pub fn new($($processor_field: $processor_type),+) -> Self {
674 Self {
675 $(
676 $processor_field,
677 )+
678 }
679 }
680 }
681 impl InPlaceStatefulProcessor<$data_type, $error_type> for $pipeline_name {
682 fn process(&mut self, data: &mut $data_type) -> Result<(), $error_type> {
683 $(
684 self.$processor_field.process(data)?;
685 )*
686 Ok(())
687 }
688 }
689 };
690 ($pipeline_name:ident, $data_type:ty, $error_type:ty, $($processor_type:ty),+) => {
691 type_flow_proc_macros::inplace_stateful_processor_pipeline_with_index!($pipeline_name, $data_type, $error_type, $($processor_type),+);
692 };
693}
694
695/// Creates a generic, stateful, in-place processor pipeline with type-level permutation capabilities.
696///
697/// This powerful macro generates a pipeline struct that is generic over its
698/// `InPlaceStatefulProcessor`s. It automatically implements traits that allow the
699/// order of processors to be rearranged at compile time through type manipulation.
700///
701/// # Supported Operations
702///
703/// The generated pipeline supports the following type-level transformations through trait implementations:
704///
705/// - `Reverse`: Reverses the order of processors in the pipeline
706/// - `ShiftLeft`: Rotates all processors one position left
707/// - `ShiftRight`: Rotates all processors one position right
708/// - `SwapStartEnd`: Exchanges the first and last processors
709/// - `SwapArbitraryProcessors<I, J>`: Swaps processors at any two positions
710///
711/// # Macro Parameters
712///
713/// ## Variant 1: With named fields
714/// - `$struct_name`: Name for the generated pipeline struct
715/// - `$processor_type`: Type of data flowing through the pipeline
716/// - `$processor_error_type`: Common error type used by all processors
717/// - `$($field_name:ident : $type_param:ident),+`: Field names and corresponding generic type parameters
718///
719/// ## Variant 2: With processor count
720/// - `$struct_name`: Name for the generated pipeline struct
721/// - `$processor_type`: Type of data flowing through the pipeline
722/// - `$processor_error_type`: Common error type used by all processors
723/// - `$number_of_processors`: A literal integer specifying how many processors the pipeline should support
724///
725/// # Examples
726///
727/// ```
728/// use type_flow_macros::{
729/// type_flow_inplace_stateful_processor_pipeline,
730/// inplace_stateful_processor
731/// };
732/// use type_flow_proc_macros::implement_processor_swapping;
733/// use type_flow_traits::{InPlaceStatefulProcessor,
734/// Reverse, ShiftLeft};
735/// #[derive(Debug)]
736/// struct MyError;
737///
738/// // These processors have a state type of `()` and don't use it.
739/// inplace_stateful_processor!(AddOne, (), i32, MyError, |_, d: &mut i32| { *d += 1; Ok(()) });
740/// inplace_stateful_processor!(MulTwo, (), i32, MyError, |_, d: &mut i32| { *d *= 2; Ok(()) });
741/// inplace_stateful_processor!(SubThree, (), i32, MyError, |_, d: &mut i32| { *d -= 3; Ok(()) });
742///
743/// // Using the variant of the macro that creates field names from type names.
744/// type_flow_inplace_stateful_processor_pipeline!(
745/// MyPipeline, i32, MyError, a: A, b: B, c: C
746/// );
747///
748/// // Original pipeline
749/// let mut pipeline = MyPipeline::new(AddOne::new(()), MulTwo::new(()), SubThree::new(()));
750/// let mut value = 10;
751/// pipeline.process(&mut value).unwrap();
752/// assert_eq!(value, 19); // (10 + 1) * 2 - 3 = 19
753///
754/// // Reversed pipeline. Note: .reverse() consumes the pipeline and returns a new type.
755/// let mut reversed_pipeline = MyPipeline::new(AddOne::new(()), MulTwo::new(()), SubThree::new(()))
756/// .reverse();
757/// let mut value_rev = 10;
758/// reversed_pipeline.process(&mut value_rev).unwrap();
759/// assert_eq!(value_rev, 15); // (10 - 3) * 2 + 1 = 15
760///
761/// // Shifted pipeline
762/// let mut shifted_pipeline = MyPipeline::new(AddOne::new(()), MulTwo::new(()), SubThree::new(()))
763/// .shift_left();
764/// let mut value_shift = 10;
765/// shifted_pipeline.process(&mut value_shift).unwrap();
766/// assert_eq!(value_shift, 18); // (10 * 2 - 3) + 1 = 18
767/// ```
768#[macro_export]
769macro_rules! type_flow_inplace_stateful_processor_pipeline {
770 ($struct_name:ident, $processor_type:ty, $processor_error_type:ty, $($field_name:ident : $type_param:ident),+) => {
771 #[implement_processor_swapping]
772 pub struct $struct_name<$($type_param: InPlaceStatefulProcessor<$processor_type, $processor_error_type>),*> {
773 _marker: std::marker::PhantomData<($($type_param),*)>,
774 $(
775 $field_name: $type_param,
776 )+
777 }
778 impl<$($type_param: InPlaceStatefulProcessor<$processor_type, $processor_error_type>),*> $struct_name<$($type_param),*> {
779 pub fn new($($field_name: $type_param),+) -> Self {
780 Self {
781 _marker: std::marker::PhantomData,
782 $(
783 $field_name,
784 )+
785 }
786 }
787 }
788 impl<$($type_param: InPlaceStatefulProcessor<$processor_type, $processor_error_type>),*> InPlaceStatefulProcessor<$processor_type, $processor_error_type> for $struct_name<$($type_param),*> {
789 fn process(&mut self, data: &mut $processor_type) -> Result<(), $processor_error_type> {
790 $(
791 self.$field_name.process(data)?;
792 )*
793 Ok(())
794 }
795 }
796 };
797 ($struct_name:ident, $processor_type:ty, $processor_error_type:ty, $number_of_processors:literal) => {
798 type_flow_proc_macros::type_flow_inplace_stateful_processor_pipeline_by_count!($struct_name, $processor_type, $processor_error_type, $number_of_processors);
799 };
800}