golem_rust/transaction/
compfn.rs

1// Copyright 2024-2025 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 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)
21}
22
23pub trait TupleOrUnit<T> {
24    fn into(self) -> T;
25}
26
27pub trait CompensationFunction<In, Out, Err> {
28    fn call(self, result: impl TupleOrUnit<Out>, input: impl TupleOrUnit<In>) -> Result<(), Err>;
29}
30
31impl<F, Err> CompensationFunction<(), (), (Err,)> for F
32where
33    F: FnOnce() -> Result<(), Err>,
34{
35    fn call(
36        self,
37        _result: impl TupleOrUnit<()>,
38        _input: impl TupleOrUnit<()>,
39    ) -> Result<(), (Err,)> {
40        self().map_err(|e| (e,))?;
41        Ok(())
42    }
43}
44
45impl<F, Out, Err> CompensationFunction<(), (Out,), (Err,)> for F
46where
47    F: FnOnce(Out) -> Result<(), Err>,
48{
49    fn call(
50        self,
51        out: impl TupleOrUnit<(Out,)>,
52        _input: impl TupleOrUnit<()>,
53    ) -> Result<(), (Err,)> {
54        let (out,) = out.into();
55        self(out).map_err(|err| (err,))
56    }
57}
58
59impl<T> TupleOrUnit<()> for T {
60    fn into(self) {}
61}
62
63macro_rules! compensation_function {
64    ($($ty:ident),*) => {
65        impl<F, $($ty),*, Out, Err> CompensationFunction<($($ty),*,), (Out,), (Err,)> for F
66        where
67            F: FnOnce(Out, $($ty),*) -> Result<(), Err>,
68        {
69            fn call(
70                self,
71                out: impl TupleOrUnit<(Out,)>,
72                input: impl TupleOrUnit<($($ty),*,)>,
73            ) -> Result<(), (Err,)> {
74                #[allow(non_snake_case)]
75                let ( $($ty,)+ ) = input.into();
76                let (out,) = out.into();
77                self(out, $($ty),*).map_err(|err| (err,))
78            }
79        }
80    }
81}
82
83macro_rules! tuple_or_unit {
84    ($($ty:ident),*) => {
85        impl<$($ty),*> TupleOrUnit<($($ty,)*)> for ($($ty,)*) {
86            fn into(self) -> ($($ty,)*) {
87                self
88            }
89        }
90    }
91}
92
93macro_rules! generate_for_tuples {
94    ($name:ident) => {
95        $name!(T1);
96        $name!(T1, T2);
97        $name!(T1, T2, T3);
98        $name!(T1, T2, T3, T4);
99        $name!(T1, T2, T3, T4, T5);
100        $name!(T1, T2, T3, T4, T5, T6);
101        $name!(T1, T2, T3, T4, T5, T6, T7);
102        $name!(T1, T2, T3, T4, T5, T6, T7, T8);
103        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
104        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
105        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
106        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
107        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
108        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
109        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
110        $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
111    };
112}
113
114generate_for_tuples!(tuple_or_unit);
115generate_for_tuples!(compensation_function);