1#[macro_export]
4macro_rules! dry_put {
5 ($ctx:expr, $var:ident) => {
6 $ctx.insert(stringify!($var), $var)
7 };
8 ($ctx:expr, $var:ident, $value:expr) => {
9 $ctx.insert(stringify!($var), $value)
10 };
11}
12
13#[macro_export]
16macro_rules! dry_put_key {
17 ($ctx:expr, $key:expr, $value:expr) => {
18 $ctx.insert($key, $value)
19 };
20}
21
22#[macro_export]
25macro_rules! dry_get {
26 ($ctx:expr, $var:ident) => {
27 $ctx.get::<_>(stringify!($var))
28 };
29}
30
31#[macro_export]
34macro_rules! dry_get_key {
35 ($ctx:expr, $key:expr) => {
36 $ctx.get::<_>($key)
37 };
38}
39
40#[macro_export]
43macro_rules! dry_require {
44 ($ctx:expr, $var:ident) => {
45 $ctx.get_required::<_>(stringify!($var))
46 };
47}
48
49#[macro_export]
52macro_rules! dry_require_key {
53 ($ctx:expr, $key:expr) => {
54 $ctx.get_required::<_>($key)
55 };
56}
57
58#[macro_export]
61macro_rules! dry_result {
62 ($ctx:expr, $trigger_name:expr, $result:expr) => {{
63 $ctx.insert($trigger_name, $result.clone());
64 $ctx.insert("result", $result);
65 }};
66}
67
68#[macro_export]
71macro_rules! wet_put_ref {
72 ($ctx:expr, $var:ident, $value:expr) => {
73 $ctx.insert_ref(stringify!($var), $value)
74 };
75 ($ctx:expr, $var:ident) => {
76 $ctx.insert_ref(stringify!($var), $var)
77 };
78}
79
80#[macro_export]
83macro_rules! wet_put_ref_key {
84 ($ctx:expr, $key:expr, $value:expr) => {
85 $ctx.insert_ref($key, $value)
86 };
87}
88
89#[macro_export]
92macro_rules! wet_put_arc {
93 ($ctx:expr, $var:ident, $value:expr) => {
94 $ctx.insert_arc(stringify!($var), $value)
95 };
96 ($ctx:expr, $var:ident) => {
97 $ctx.insert_arc(stringify!($var), $var)
98 };
99}
100
101#[macro_export]
104macro_rules! wet_put_arc_key {
105 ($ctx:expr, $key:expr, $value:expr) => {
106 $ctx.insert_arc($key, $value)
107 };
108}
109
110#[macro_export]
113macro_rules! wet_get_ref {
114 ($ctx:expr, $var:ident) => {
115 $ctx.get_ref::<_>(stringify!($var))
116 };
117}
118
119#[macro_export]
122macro_rules! wet_get_ref_key {
123 ($ctx:expr, $key:expr) => {
124 $ctx.get_ref::<_>($key)
125 };
126}
127
128#[macro_export]
131macro_rules! wet_require_ref {
132 ($ctx:expr, $var:ident) => {
133 $ctx.get_required::<_>(stringify!($var))
134 };
135}
136
137#[macro_export]
140macro_rules! wet_require_ref_key {
141 ($ctx:expr, $key:expr) => {
142 $ctx.get_required::<_>($key)
143 };
144}
145
146#[derive(Debug, Clone)]
148pub enum AggregationStrategy {
149 All,
151 Last,
153 First,
155 Merge,
157 Unit,
159}
160
161#[macro_export]
189macro_rules! batch {
190 ($name:ident<$T:ty> = [$($op:expr),+ $(,)?]) => {
192 batch!($name<$T> -> all = [$($op),+]);
193 };
194
195 ($name:ident<$T:ty> -> $strategy:ident = [$($op:expr),+ $(,)?]) => {
197 #[derive(Debug, Clone)]
198 pub struct $name {
199 batch: $crate::BatchOp<$T>,
200 strategy: $crate::macros::AggregationStrategy,
201 }
202
203 impl $name {
204 pub fn new() -> Self {
205 let ops: Vec<std::sync::Arc<dyn $crate::Op<$T>>> = vec![
206 $(std::sync::Arc::new($op)),+
207 ];
208 Self {
209 batch: $crate::BatchOp::new(ops),
210 strategy: batch!(@strategy $strategy),
211 }
212 }
213
214 pub fn with_continue_on_error(mut self, continue_on_error: bool) -> Self {
215 self.batch = self.batch.with_continue_on_error(continue_on_error);
216 self
217 }
218 }
219
220 impl Default for $name {
221 fn default() -> Self {
222 Self::new()
223 }
224 }
225
226 batch!(@impl $name<$T> -> $strategy);
227 };
228
229 (@strategy all) => { $crate::macros::AggregationStrategy::All };
231 (@strategy last) => { $crate::macros::AggregationStrategy::Last };
232 (@strategy first) => { $crate::macros::AggregationStrategy::First };
233 (@strategy merge) => { $crate::macros::AggregationStrategy::Merge };
234 (@strategy unit) => { $crate::macros::AggregationStrategy::Unit };
235
236 (@impl $name:ident<$T:ty> -> all) => {
238 #[async_trait::async_trait]
239 impl $crate::Op<Vec<$T>> for $name {
240 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<Vec<$T>> {
241 self.batch.perform(dry, wet).await
242 }
243
244 fn metadata(&self) -> $crate::OpMetadata {
245 self.batch.metadata()
246 }
247 }
248 };
249
250 (@impl $name:ident<$T:ty> -> last) => {
252 #[async_trait::async_trait]
253 impl $crate::Op<$T> for $name {
254 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
255 let results = self.batch.perform(dry, wet).await?;
256 results.into_iter().last()
257 .ok_or_else(|| $crate::OpError::ExecutionFailed("No results from batch operation".to_string()))
258 }
259
260 fn metadata(&self) -> $crate::OpMetadata {
261 self.batch.metadata()
262 }
263 }
264 };
265
266 (@impl $name:ident<$T:ty> -> first) => {
268 #[async_trait::async_trait]
269 impl $crate::Op<$T> for $name {
270 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
271 let results = self.batch.perform(dry, wet).await?;
272 results.into_iter().next()
273 .ok_or_else(|| $crate::OpError::ExecutionFailed("No results from batch operation".to_string()))
274 }
275
276 fn metadata(&self) -> $crate::OpMetadata {
277 self.batch.metadata()
278 }
279 }
280 };
281
282 (@impl $name:ident<$T:ty> -> unit) => {
284 #[async_trait::async_trait]
285 impl $crate::Op<()> for $name {
286 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<()> {
287 let _results = self.batch.perform(dry, wet).await?;
288 Ok(())
289 }
290
291 fn metadata(&self) -> $crate::OpMetadata {
292 self.batch.metadata()
293 }
294 }
295 };
296
297 (@impl $name:ident<$T:ty> -> merge) => {
299 #[async_trait::async_trait]
300 impl $crate::Op<$T> for $name
301 where
302 $T: Default + Clone
303 {
304 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
305 let results = self.batch.perform(dry, wet).await?;
306 Ok(results.into_iter().last().unwrap_or_default())
308 }
309
310 fn metadata(&self) -> $crate::OpMetadata {
311 self.batch.metadata()
312 }
313 }
314 };
315}
316
317#[macro_export]
340macro_rules! repeat {
341 ($name:ident<$T:ty> = {
343 counter: $counter:expr,
344 limit: $limit_var:expr,
345 ops: [$($op:expr),+ $(,)?]
346 }) => {
347 repeat!($name<$T> -> all = {
348 counter: $counter,
349 limit: $limit_var,
350 ops: [$($op),+]
351 });
352 };
353
354 ($name:ident<$T:ty> = {
356 counter: $counter:expr,
357 limit: $limit_var:expr,
358 continue_on_error: $continue_on_error:expr,
359 ops: [$($op:expr),+ $(,)?]
360 }) => {
361 repeat!($name<$T> -> all = {
362 counter: $counter,
363 limit: $limit_var,
364 continue_on_error: $continue_on_error,
365 ops: [$($op),+]
366 });
367 };
368
369 ($name:ident<$T:ty> -> $strategy:ident = {
371 counter: $counter:expr,
372 limit: $limit_var:expr,
373 ops: [$($op:expr),+ $(,)?]
374 }) => {
375 repeat!($name<$T> -> $strategy = {
376 counter: $counter,
377 limit: $limit_var,
378 continue_on_error: false,
379 ops: [$($op),+]
380 });
381 };
382
383 ($name:ident<$T:ty> -> $strategy:ident = {
385 counter: $counter:expr,
386 limit: $limit_var:expr,
387 continue_on_error: $continue_on_error:expr,
388 ops: [$($op:expr),+ $(,)?]
389 }) => {
390 #[derive(Debug, Clone)]
391 pub struct $name {
392 counter_var: String,
393 limit_var: String,
394 continue_on_error: bool,
395 strategy: $crate::macros::AggregationStrategy,
396 }
397
398 impl $name {
399 pub fn new() -> Self {
400 Self {
401 counter_var: $counter.to_string(),
402 limit_var: $limit_var.to_string(),
403 continue_on_error: $continue_on_error,
404 strategy: repeat!(@strategy $strategy),
405 }
406 }
407
408 fn create_ops() -> Vec<std::sync::Arc<dyn $crate::Op<$T>>> {
409 vec![
410 $(std::sync::Arc::new($op)),+
411 ]
412 }
413 }
414
415 impl Default for $name {
416 fn default() -> Self {
417 Self::new()
418 }
419 }
420
421 repeat!(@impl $name<$T> -> $strategy);
422
423 impl $name {
424 fn build_metadata(&self) -> $crate::OpMetadata {
425 let limit_var = self.limit_var.clone();
426 let mut properties = serde_json::Map::new();
427 properties.insert(
428 limit_var.clone(),
429 serde_json::json!({ "type": "integer", "minimum": 0 })
430 );
431
432 $crate::OpMetadata::builder(stringify!($name))
433 .description(format!("For-loop with dynamic limit from '{}'", limit_var))
434 .input_schema(serde_json::json!({
435 "type": "object",
436 "properties": properties,
437 "required": [limit_var]
438 }))
439 .build()
440 }
441 }
442 };
443
444 (@strategy all) => { $crate::macros::AggregationStrategy::All };
446 (@strategy last) => { $crate::macros::AggregationStrategy::Last };
447 (@strategy first) => { $crate::macros::AggregationStrategy::First };
448 (@strategy merge) => { $crate::macros::AggregationStrategy::Merge };
449 (@strategy unit) => { $crate::macros::AggregationStrategy::Unit };
450
451 (@impl $name:ident<$T:ty> -> all) => {
453 #[async_trait::async_trait]
454 impl $crate::Op<Vec<$T>> for $name {
455 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<Vec<$T>> {
456 let limit = dry.get_required::<usize>(&self.limit_var)?;
457 let ops = Self::create_ops();
458 let loop_op = $crate::loop_op::LoopOp::new(
459 self.counter_var.clone(),
460 limit,
461 ops
462 ).with_continue_on_error(self.continue_on_error);
463 loop_op.perform(dry, wet).await
464 }
465
466 fn metadata(&self) -> $crate::OpMetadata {
467 self.build_metadata()
468 }
469 }
470 };
471
472 (@impl $name:ident<$T:ty> -> last) => {
474 #[async_trait::async_trait]
475 impl $crate::Op<$T> for $name {
476 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
477 let limit = dry.get_required::<usize>(&self.limit_var)?;
478 let ops = Self::create_ops();
479 let loop_op = $crate::loop_op::LoopOp::new(
480 self.counter_var.clone(),
481 limit,
482 ops
483 ).with_continue_on_error(self.continue_on_error);
484 let results = loop_op.perform(dry, wet).await?;
485 results.into_iter().last()
486 .ok_or_else(|| $crate::OpError::ExecutionFailed("No results from repeat operation".to_string()))
487 }
488
489 fn metadata(&self) -> $crate::OpMetadata {
490 self.build_metadata()
491 }
492 }
493 };
494
495 (@impl $name:ident<$T:ty> -> first) => {
497 #[async_trait::async_trait]
498 impl $crate::Op<$T> for $name {
499 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
500 let limit = dry.get_required::<usize>(&self.limit_var)?;
501 let ops = Self::create_ops();
502 let loop_op = $crate::loop_op::LoopOp::new(
503 self.counter_var.clone(),
504 limit,
505 ops
506 ).with_continue_on_error(self.continue_on_error);
507 let results = loop_op.perform(dry, wet).await?;
508 results.into_iter().next()
509 .ok_or_else(|| $crate::OpError::ExecutionFailed("No results from repeat operation".to_string()))
510 }
511
512 fn metadata(&self) -> $crate::OpMetadata {
513 self.build_metadata()
514 }
515 }
516 };
517
518 (@impl $name:ident<$T:ty> -> unit) => {
520 #[async_trait::async_trait]
521 impl $crate::Op<()> for $name {
522 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<()> {
523 let limit = dry.get_required::<usize>(&self.limit_var)?;
524 let ops = Self::create_ops();
525 let loop_op = $crate::loop_op::LoopOp::new(
526 self.counter_var.clone(),
527 limit,
528 ops
529 ).with_continue_on_error(self.continue_on_error);
530 let _results = loop_op.perform(dry, wet).await?;
531 Ok(())
532 }
533
534 fn metadata(&self) -> $crate::OpMetadata {
535 self.build_metadata()
536 }
537 }
538 };
539
540 (@impl $name:ident<$T:ty> -> merge) => {
542 #[async_trait::async_trait]
543 impl $crate::Op<$T> for $name
544 where
545 $T: Default + Clone
546 {
547 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
548 let limit = dry.get_required::<usize>(&self.limit_var)?;
549 let ops = Self::create_ops();
550 let loop_op = $crate::loop_op::LoopOp::new(
551 self.counter_var.clone(),
552 limit,
553 ops
554 ).with_continue_on_error(self.continue_on_error);
555 let results = loop_op.perform(dry, wet).await?;
556 Ok(results.into_iter().last().unwrap_or_default())
557 }
558
559 fn metadata(&self) -> $crate::OpMetadata {
560 self.build_metadata()
561 }
562 }
563 };
564}
565
566#[macro_export]
592macro_rules! repeat_until {
593 ($name:ident<$T:ty> = {
595 counter: $counter:expr,
596 condition: $condition_var:expr,
597 max_iterations: $max:expr,
598 ops: [$($op:expr),+ $(,)?]
599 }) => {
600 repeat_until!($name<$T> -> all = {
601 counter: $counter,
602 condition: $condition_var,
603 max_iterations: $max,
604 ops: [$($op),+]
605 });
606 };
607
608 ($name:ident<$T:ty> -> $strategy:ident = {
610 counter: $counter:expr,
611 condition: $condition_var:expr,
612 max_iterations: $max:expr,
613 ops: [$($op:expr),+ $(,)?]
614 }) => {
615 #[derive(Debug, Clone)]
616 pub struct $name {
617 counter_var: String,
618 condition_var: String,
619 max_iterations: usize,
620 strategy: $crate::macros::AggregationStrategy,
621 continue_var: String,
623 break_var: String,
624 loop_id: String,
625 }
626
627 impl $name {
628 pub fn new() -> Self {
629 let loop_id = ::uuid::Uuid::new_v4().to_string();
632 Self {
633 counter_var: $counter.to_string(),
634 condition_var: $condition_var.to_string(),
635 max_iterations: $max,
636 strategy: repeat_until!(@strategy $strategy),
637 continue_var: format!("__continue_loop_{}", loop_id),
638 break_var: format!("__break_loop_{}", loop_id),
639 loop_id,
640 }
641 }
642
643 fn create_ops() -> Vec<std::sync::Arc<dyn $crate::Op<$T>>> {
644 vec![
645 $(std::sync::Arc::new($op)),+
646 ]
647 }
648
649 async fn perform_repeat_until(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<Vec<$T>> {
650 let mut results = Vec::new();
651 let mut iteration = 0;
652
653 dry.insert("__current_loop_id", &self.loop_id);
655
656 while iteration < self.max_iterations {
657 let should_continue = dry.get::<bool>(&self.condition_var)
659 .unwrap_or(false);
660
661 if !should_continue {
662 break;
663 }
664
665 dry.insert(&self.counter_var, iteration);
667
668 dry.insert(&self.continue_var, false);
670 dry.insert(&self.break_var, false);
671
672 let ops = Self::create_ops();
674 for op in ops {
675 let result = op.perform(dry, wet).await?;
676 results.push(result);
677
678 if dry.is_aborted() {
680 return Err($crate::OpError::Aborted(
681 dry.abort_reason().cloned().unwrap_or_else(|| "While loop aborted".to_string())
682 ));
683 }
684
685 if dry.get::<bool>(&self.continue_var).unwrap_or(false) {
687 dry.insert(&self.continue_var, false); break; }
690
691 if dry.get::<bool>(&self.break_var).unwrap_or(false) {
693 dry.insert(&self.break_var, false); return Ok(results); }
696 }
697
698 iteration += 1;
699 }
700
701 Ok(results)
702 }
703 }
704
705 impl Default for $name {
706 fn default() -> Self {
707 Self::new()
708 }
709 }
710
711 repeat_until!(@impl $name<$T> -> $strategy);
712
713 impl $name {
714 fn build_metadata(&self) -> $crate::OpMetadata {
715 let condition_var = self.condition_var.clone();
716 let mut properties = serde_json::Map::new();
717 properties.insert(
718 condition_var.clone(),
719 serde_json::json!({ "type": "boolean" })
720 );
721
722 $crate::OpMetadata::builder(stringify!($name))
723 .description(format!("While-loop with condition from '{}' (max {} iterations)", condition_var, self.max_iterations))
724 .input_schema(serde_json::json!({
725 "type": "object",
726 "properties": properties,
727 "required": [condition_var]
728 }))
729 .build()
730 }
731 }
732 };
733
734 (@strategy all) => { $crate::macros::AggregationStrategy::All };
736 (@strategy last) => { $crate::macros::AggregationStrategy::Last };
737 (@strategy first) => { $crate::macros::AggregationStrategy::First };
738 (@strategy merge) => { $crate::macros::AggregationStrategy::Merge };
739 (@strategy unit) => { $crate::macros::AggregationStrategy::Unit };
740
741 (@impl $name:ident<$T:ty> -> all) => {
743 #[async_trait::async_trait]
744 impl $crate::Op<Vec<$T>> for $name {
745 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<Vec<$T>> {
746 self.perform_repeat_until(dry, wet).await
747 }
748
749 fn metadata(&self) -> $crate::OpMetadata {
750 self.build_metadata()
751 }
752 }
753 };
754
755 (@impl $name:ident<$T:ty> -> last) => {
757 #[async_trait::async_trait]
758 impl $crate::Op<$T> for $name {
759 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
760 let results = self.perform_repeat_until(dry, wet).await?;
761 results.into_iter().last()
762 .ok_or_else(|| $crate::OpError::ExecutionFailed("No results from while loop operation".to_string()))
763 }
764
765 fn metadata(&self) -> $crate::OpMetadata {
766 self.build_metadata()
767 }
768 }
769 };
770
771 (@impl $name:ident<$T:ty> -> first) => {
773 #[async_trait::async_trait]
774 impl $crate::Op<$T> for $name {
775 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
776 let results = self.perform_repeat_until(dry, wet).await?;
777 results.into_iter().next()
778 .ok_or_else(|| $crate::OpError::ExecutionFailed("No results from while loop operation".to_string()))
779 }
780
781 fn metadata(&self) -> $crate::OpMetadata {
782 self.build_metadata()
783 }
784 }
785 };
786
787 (@impl $name:ident<$T:ty> -> unit) => {
789 #[async_trait::async_trait]
790 impl $crate::Op<()> for $name {
791 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<()> {
792 let _results = self.perform_repeat_until(dry, wet).await?;
793 Ok(())
794 }
795
796 fn metadata(&self) -> $crate::OpMetadata {
797 self.build_metadata()
798 }
799 }
800 };
801
802 (@impl $name:ident<$T:ty> -> merge) => {
804 #[async_trait::async_trait]
805 impl $crate::Op<$T> for $name
806 where
807 $T: Default + Clone
808 {
809 async fn perform(&self, dry: &mut $crate::DryContext, wet: &mut $crate::WetContext) -> $crate::OpResult<$T> {
810 let results = self.perform_repeat_until(dry, wet).await?;
811 Ok(results.into_iter().last().unwrap_or_default())
812 }
813
814 fn metadata(&self) -> $crate::OpMetadata {
815 self.build_metadata()
816 }
817 }
818 };
819}
820
821#[macro_export]
825macro_rules! op_wrapper {
826 (unit $name:ident for $from:ty) => {
828 pub struct $name<T>
829 where
830 T: $crate::Op<$from> + Send + Sync,
831 {
832 inner: T,
833 }
834
835 impl<T> $name<T>
836 where
837 T: $crate::Op<$from> + Send + Sync,
838 {
839 pub fn new(op: T) -> Self {
840 Self { inner: op }
841 }
842 }
843
844 #[async_trait::async_trait]
845 impl<T> $crate::Op<()> for $name<T>
846 where
847 T: $crate::Op<$from> + Send + Sync,
848 {
849 async fn perform(
850 &self,
851 dry: &mut $crate::DryContext,
852 wet: &mut $crate::WetContext,
853 ) -> $crate::OpResult<()> {
854 let _result = self.inner.perform(dry, wet).await?;
855 Ok(())
856 }
857
858 fn metadata(&self) -> $crate::OpMetadata {
859 self.inner.metadata()
860 }
861 }
862 };
863
864 (last $name:ident for $elem:ty) => {
866 pub struct $name<T>
867 where
868 T: $crate::Op<Vec<$elem>> + Send + Sync,
869 {
870 inner: T,
871 _phantom: std::marker::PhantomData<$elem>,
872 }
873
874 impl<T> $name<T>
875 where
876 T: $crate::Op<Vec<$elem>> + Send + Sync,
877 {
878 pub fn new(op: T) -> Self {
879 Self {
880 inner: op,
881 _phantom: std::marker::PhantomData,
882 }
883 }
884 }
885
886 #[async_trait::async_trait]
887 impl<T> $crate::Op<$elem> for $name<T>
888 where
889 T: $crate::Op<Vec<$elem>> + Send + Sync,
890 {
891 async fn perform(
892 &self,
893 dry: &mut $crate::DryContext,
894 wet: &mut $crate::WetContext,
895 ) -> $crate::OpResult<$elem> {
896 let results = self.inner.perform(dry, wet).await?;
897 results.into_iter().last().ok_or_else(|| {
898 $crate::OpError::ExecutionFailed(
899 "No results from wrapped operation".to_string(),
900 )
901 })
902 }
903
904 fn metadata(&self) -> $crate::OpMetadata {
905 self.inner.metadata()
906 }
907 }
908 };
909}
910
911#[macro_export]
927macro_rules! abort {
928 ($dry:expr) => {{
929 $dry.set_abort(None);
930 return Err($crate::OpError::Aborted("Operation aborted".to_string()));
931 }};
932 ($dry:expr, $reason:expr) => {{
933 let reason_str = $reason.to_string();
934 $dry.set_abort(Some(reason_str.clone()));
935 return Err($crate::OpError::Aborted(reason_str));
936 }};
937}
938
939#[macro_export]
955macro_rules! continue_loop {
956 ($dry:expr) => {{
957 if let Some(loop_id) = $dry.get::<String>("__current_loop_id") {
959 let continue_var = format!("__continue_loop_{}", loop_id);
960 $dry.insert(&continue_var, true);
961 }
962 return Ok(Default::default()); }};
964}
965
966#[macro_export]
982macro_rules! break_loop {
983 ($dry:expr) => {{
984 if let Some(loop_id) = $dry.get::<String>("__current_loop_id") {
986 let break_var = format!("__break_loop_{}", loop_id);
987 $dry.insert(&break_var, true);
988 }
989 return Ok(Default::default()); }};
991}
992
993#[macro_export]
1004macro_rules! break_loop_scoped {
1005 ($dry:expr, $loop_id:expr) => {{
1006 let break_var = format!("__break_loop_{}", $loop_id);
1007 $dry.insert(&break_var, true);
1008 return Ok(Default::default()); }};
1010}
1011
1012#[macro_export]
1026macro_rules! check_abort {
1027 ($dry:expr) => {
1028 if $dry.is_aborted() {
1029 let reason = $dry
1030 .abort_reason()
1031 .cloned()
1032 .unwrap_or_else(|| "Operation aborted".to_string());
1033 return Err($crate::OpError::Aborted(reason));
1034 }
1035 };
1036}
1037
1038#[macro_export]
1040macro_rules! void_op {
1041 ($wrapper_name:ident, $op_type:ty) => {
1042 #[derive(Clone)]
1043 pub struct $wrapper_name {
1044 wrapped: $op_type,
1045 }
1046
1047 impl $wrapper_name {
1048 pub fn new() -> Self {
1049 Self {
1050 wrapped: <$op_type>::new(),
1051 }
1052 }
1053 }
1054
1055 #[async_trait::async_trait]
1056 impl $crate::Op<()> for $wrapper_name {
1057 async fn perform(&self, dry: &mut DryContext, wet: &mut WetContext) -> OpResult<()> {
1058 self.wrapped.perform(dry, wet).await.map(|_| ())
1059 }
1060
1061 fn metadata(&self) -> OpMetadata {
1062 self.wrapped.metadata()
1063 }
1064
1065 async fn rollback(&self, dry: &mut DryContext, wet: &mut WetContext) -> OpResult<()> {
1066 self.wrapped.rollback(dry, wet).await
1067 }
1068 }
1069 };
1070}
1071
1072#[macro_export]
1092macro_rules! wire_trigger {
1093 ($wrapper_name:ident, $op_type:ty, $name:expr) => {
1094 paste::paste! {
1095 $crate::void_op!([<$wrapper_name VoidOp>], $op_type);
1097
1098 pub struct $wrapper_name {
1099 name: String,
1100 action: [<$wrapper_name VoidOp>],
1101 }
1102
1103 impl $wrapper_name {
1104 pub fn new() -> Self {
1105 Self {
1106 name: $name.to_string(),
1107 action: [<$wrapper_name VoidOp>]::new(),
1108 }
1109 }
1110 }
1111 }
1112
1113 impl Default for $wrapper_name {
1114 fn default() -> Self {
1115 Self::new()
1116 }
1117 }
1118
1119 #[async_trait::async_trait]
1120 impl $crate::Trigger for $wrapper_name {
1121 fn name(&self) -> String {
1122 self.name.clone()
1123 }
1124
1125 fn actions(&self) -> Vec<Arc<dyn $crate::Op<()>>> {
1126 vec![Arc::new(self.action.clone())]
1127 }
1128
1129 fn predicate(&self) -> Arc<dyn $crate::Op<bool>> {
1130 Arc::new($crate::TrivialPredicate::default())
1131 }
1132 }
1133 };
1134
1135 ($wrapper_name:ident, $op_type:ty, $name:expr, $predicate:expr) => {
1136 paste::paste! {
1137 $crate::void_op!([<$wrapper_name VoidOp>], $op_type);
1139
1140 pub struct $wrapper_name {
1141 name: String,
1142 action: [<$wrapper_name VoidOp>],
1143 predicate: Arc<dyn $crate::Op<bool>>,
1144 }
1145
1146 impl $wrapper_name {
1147 pub fn new() -> Self {
1148 Self {
1149 name: $name.to_string(),
1150 action: [<$wrapper_name VoidOp>]::new(),
1151 predicate: Arc::new($predicate),
1152 }
1153 }
1154
1155 pub fn with_predicate(name: String, predicate: Arc<dyn $crate::Op<bool>>) -> Self {
1156 Self {
1157 name,
1158 action: [<$wrapper_name VoidOp>]::new(),
1159 predicate,
1160 }
1161 }
1162 }
1163 }
1164
1165 impl Default for $wrapper_name {
1166 fn default() -> Self {
1167 Self::new()
1168 }
1169 }
1170
1171 #[async_trait::async_trait]
1172 impl $crate::Trigger for $wrapper_name {
1173 fn name(&self) -> String {
1174 self.name.clone()
1175 }
1176 fn predicate(&self) -> Arc<dyn $crate::Op<bool>> {
1177 Arc::clone(&self.predicate)
1178 }
1179 fn actions(&self) -> Vec<Arc<dyn $crate::Op<()>>> {
1180 vec![Arc::new(self.action.clone())]
1181 }
1182 }
1183 };
1184}