gimo v0.1.0
Loading...
Searching...
No Matches
TransformError.hpp
Go to the documentation of this file.
1// Copyright Dominic (DNKpp) Koepke 2025.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef GIMO_ALGORITHM_TRANSFORM_ERROR_HPP
7#define GIMO_ALGORITHM_TRANSFORM_ERROR_HPP
8
9#pragma once
10
11#include "gimo/Common.hpp"
12#include "gimo/Pipeline.hpp"
14
15#include <functional>
16#include <tuple>
17#include <type_traits>
18#include <utility>
19
20namespace gimo::detail::transform_error
21{
22 template <typename Expected, typename Action>
23 consteval Expected* print_diagnostics()
24 {
25 if constexpr (!expected_like<Expected>)
26 {
27 static_assert(always_false_v<Expected>, "The transform_error algorithm requires an expected-like input.");
28 }
29 else if constexpr (!std::is_invocable_v<Action, error_result_t<Expected>>)
30 {
31 static_assert(always_false_v<Expected>, "The transform_error algorithm requires an action invocable with the expected's error.");
32 }
33 else if constexpr (!rebindable_error_to<Expected, std::invoke_result_t<Action, error_result_t<Expected>>>)
34 {
35 static_assert(always_false_v<Expected>, "The transform_error algorithm requires an expected-like whose error-type can be rebound.");
36 }
37
38 return nullptr;
39 }
40
41 template <typename Expected, typename Action>
42 using result_t = rebind_error_t<
43 Expected,
44 std::invoke_result_t<Action, error_result_t<Expected>>>;
45
46 template <typename Action, expected_like Expected>
47 [[nodiscard]]
48 constexpr result_t<Expected, Action> on_value([[maybe_unused]] Action&& action, Expected&& closure)
49 {
50 return detail::rebind_value<result_t<Expected, Action>, Expected>(closure);
51 }
52
53 template <typename Action, expected_like Expected, typename Next, typename... Steps>
54 [[nodiscard]]
55 constexpr auto on_value(
56 Action&& action,
57 Expected&& closure,
58 Next&& next,
59 Steps&&... steps)
60 {
61 return std::forward<Next>(next).on_value(
62 transform_error::on_value(std::forward<Action>(action), std::forward<Expected>(closure)),
63 std::forward<Steps>(steps)...);
64 }
65
66 template <typename Action, expected_like Expected>
67 [[nodiscard]]
68 constexpr result_t<Expected, Action> on_null(Action&& action, Expected&& closure)
69 {
70 return detail::construct_from_error<result_t<Expected, Action>>(
71 std::invoke(
72 std::forward<Action>(action),
73 detail::forward_error<Expected>(closure)));
74 }
75
76 template <typename Action, expected_like Expected, typename Next, typename... Steps>
77 [[nodiscard]]
78 constexpr auto on_null(Action&& action, Expected&& closure, Next&& next, Steps&&... steps)
79 {
80 return std::forward<Next>(next).on_null(
81 transform_error::on_null(std::forward<Action>(action), std::forward<Expected>(closure)),
82 std::forward<Steps>(steps)...);
83 }
84
85 struct traits
86 {
87 template <nullable Expected, typename Action>
88 static constexpr bool is_applicable_on = requires {
89 requires rebindable_error_to<
90 Expected,
91 std::invoke_result_t<Action, error_result_t<Expected>>>;
92 };
93
94 template <typename Action, nullable Expected, typename... Steps>
95 [[nodiscard]]
96 static constexpr auto on_value(Action&& action, Expected&& closure, Steps&&... steps)
97 {
98 if constexpr (is_applicable_on<Expected, Action>)
99 {
100 return transform_error::on_value(
101 std::forward<Action>(action),
102 std::forward<Expected>(closure),
103 std::forward<Steps>(steps)...);
104 }
105 else
106 {
107 return *transform_error::print_diagnostics<Expected, Action>();
108 }
109 }
110
111 template <typename Action, nullable Expected, typename... Steps>
112 [[nodiscard]]
113 static constexpr auto on_null(Action&& action, Expected&& closure, Steps&&... steps)
114 {
115 if constexpr (is_applicable_on<Expected, Action>)
116 {
117 return transform_error::on_null(
118 std::forward<Action>(action),
119 std::forward<Expected>(closure),
120 std::forward<Steps>(steps)...);
121 }
122 else
123 {
124 return *transform_error::print_diagnostics<Expected, Action>();
125 }
126 }
127 };
128}
129
130namespace gimo
131{
132 namespace detail
133 {
134 template <typename Action>
135 using transform_error_t = BasicAlgorithm<transform_error::traits, std::remove_cvref_t<Action>>;
136 }
137
157 template <typename Action>
158 [[nodiscard]]
159 constexpr auto transform_error(Action&& action)
160 {
161 using Algorithm = detail::transform_error_t<Action>;
162
163 return Pipeline{std::tuple<Algorithm>{std::forward<Action>(action)}};
164 }
165}
166
167#endif
A composite object representing a sequence of monadic operations.
Definition Pipeline.hpp:30
constexpr auto transform_error(Action &&action)
Creates a pipeline step that transforms the error of an expected-like type.
Definition TransformError.hpp:159
Definition AndThen.hpp:21
typename traits< std::remove_cvref_t< Expected > >::template rebind_error< std::remove_cvref_t< Error > > rebind_error_t
Helper alias to obtain the Expected type with the rebound Error type.
Definition Common.hpp:416