Skip to main content

golem_rust/transaction/
compfn.rs

1// Copyright 2024-2026 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub async fn call_compensation_function<In, Out, Err>(
16    f: impl CompensationFunction<In, Out, Err>,
17    result: impl TupleOrUnit<Out>,
18    input: impl TupleOrUnit<In>,
19) -> Result<(), Err> {
20    f.call(result, input).await
21}
22
23pub trait TupleOrUnit<T> {
24    fn into(self) -> T;
25}
26
27#[allow(async_fn_in_trait)]
28pub trait CompensationFunction<In, Out, Err> {
29    async fn call(
30        self,
31        result: impl TupleOrUnit<Out>,
32        input: impl TupleOrUnit<In>,
33    ) -> Result<(), Err>;
34}
35
36impl<F, Err> CompensationFunction<(), (), (Err,)> for F
37where
38    F: FnOnce() -> Result<(), Err>,
39{
40    async fn call(
41        self,
42        _result: impl TupleOrUnit<()>,
43        _input: impl TupleOrUnit<()>,
44    ) -> Result<(), (Err,)> {
45        self().map_err(|e| (e,))?;
46        Ok(())
47    }
48}
49
50impl<F, Out, Err> CompensationFunction<(), (Out,), (Err,)> for F
51where
52    F: FnOnce(Out) -> Result<(), Err>,
53{
54    async fn call(
55        self,
56        out: impl TupleOrUnit<(Out,)>,
57        _input: impl TupleOrUnit<()>,
58    ) -> Result<(), (Err,)> {
59        let (out,) = out.into();
60        self(out).map_err(|err| (err,))
61    }
62}
63
64impl<T> TupleOrUnit<()> for T {
65    fn into(self) {}
66}
67
68macro_rules! compensation_function {
69    ($($ty:ident),*) => {
70        impl<F, $($ty),*, Out, Err> CompensationFunction<($($ty),*,), (Out,), (Err,)> for F
71        where
72            F: FnOnce(Out, $($ty),*) -> Result<(), Err>,
73        {
74            async fn call(
75                self,
76                out: impl TupleOrUnit<(Out,)>,
77                input: impl TupleOrUnit<($($ty),*,)>,
78            ) -> Result<(), (Err,)> {
79                #[allow(non_snake_case)]
80                let ( $($ty,)+ ) = input.into();
81                let (out,) = out.into();
82                self(out, $($ty),*).map_err(|err| (err,))
83            }
84        }
85    }
86}
87
88macro_rules! tuple_or_unit {
89    ($($ty:ident),*) => {
90        impl<$($ty),*> TupleOrUnit<($($ty,)*)> for ($($ty,)*) {
91            fn into(self) -> ($($ty,)*) {
92                self
93            }
94        }
95    }
96}
97
98macro_rules! generate_for_tuples {
99    ($name:ident) => {
100        $name!(T1);
101        $name!(T1, T2);
102        $name!(T1, T2, T3);
103        $name!(T1, T2, T3, T4);
104        $name!(T1, T2, T3, T4, T5);
105        $name!(T1, T2, T3, T4, T5, T6);
106        $name!(T1, T2, T3, T4, T5, T6, T7);
107        $name!(T1, T2, T3, T4, T5, T6, T7, T8);
108        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
109        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
110        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
111        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
112        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
113        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
114        $name!(
115            T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
116        );
117        $name!(
118            T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16
119        );
120    };
121}
122
123generate_for_tuples!(tuple_or_unit);
124generate_for_tuples!(compensation_function);