libquentier 0.8.0
The library for rich desktop clients of Evernote service
Loading...
Searching...
No Matches
Result.h
1/*
2 * Copyright 2023-2024 Dmitry Ivanov
3 *
4 * This file is part of libquentier
5 *
6 * libquentier is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, version 3 of the License.
9 *
10 * libquentier is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with libquentier. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#pragma once
20
21#include <quentier/exception/RuntimeError.h>
22#include <quentier/types/ErrorString.h>
23
24#include <type_traits>
25#include <variant>
26
27namespace quentier {
28
33template <
34 class T, class Error,
35 typename = typename std::enable_if_t<
36 !std::is_same_v<std::decay_t<T>, std::decay_t<Error>>>>
37class Result
38{
39 using ValueType = std::conditional_t<
40 std::is_same_v<std::decay_t<T>, void>, std::monostate, T>;
41
42public:
43 template <
44 typename T1 = T,
45 typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
46 nullptr>
47 explicit Result(T1 t) : m_valueOrError{std::move(t)}
48 {}
49
50 template <
51 typename T1 = T,
52 typename std::enable_if_t<std::is_void_v<std::decay_t<T1>>> * = nullptr>
53 explicit Result() : m_valueOrError{std::monostate{}}
54 {}
55
56 explicit Result(Error error) : m_valueOrError{std::move(error)} {}
57
59 m_valueOrError{other.m_valueOrError}
60 {}
61
63 m_valueOrError{std::move(other.m_valueOrError)}
64 {}
65
66 Result & operator=(const Result<T, Error> & other)
67 {
68 if (this != &other) {
69 m_valueOrError = other.m_valueOrError;
70 }
71
72 return *this;
73 }
74
75 Result & operator=(Result<T, Error> && other)
76 {
77 if (this != &other) {
78 m_valueOrError = std::move(other.m_valueOrError);
79 }
80
81 return *this;
82 }
83
88 {
89 return std::holds_alternative<ValueType>(m_valueOrError);
90 }
91
92 operator bool() const noexcept
93 {
94 return isValid();
95 }
96
97 template <
98 typename T1 = T,
99 typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
100 nullptr>
101 [[nodiscard]] T1 & get()
102 {
103 // NOTE: std::get also performs the check of what is stored inside the
104 // variant but it throws std::bad_variant_access which doesn't implement
105 // QException so this exception is not representable inside QFuture
106 // in Qt5. Due to this for Qt5 also performing another check and using
107 // another exception type
108#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
109 if (Q_UNLIKELY(!isValid())) {
110 throw RuntimeError{
111 ErrorString{"Detected attempt to get value from empty Result"}};
112 }
113#endif
114
115 return std::get<T>(m_valueOrError);
116 }
117
118 template <
119 typename T1 = T,
120 typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
121 nullptr>
122 [[nodiscard]] const T1 & get() const
123 {
124 // NOTE: std::get also performs the check of what is stored inside the
125 // variant but it throws std::bad_variant_access which doesn't implement
126 // QException so this exception is not representable inside QFuture
127 // in Qt5. Due to this for Qt5 also performing another check and using
128 // another exception type
129#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
130 if (Q_UNLIKELY(!isValid())) {
131 throw RuntimeError{
132 ErrorString{"Detected attempt to get value from empty Result"}};
133 }
134#endif
135
136 return std::get<T>(m_valueOrError);
137 }
138
139 template <
140 typename T1 = T,
141 typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
142 nullptr>
143 [[nodiscard]] T1 & operator*()
144 {
145 return get();
146 }
147
148 template <
149 typename T1 = T,
150 typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
151 nullptr>
152 [[nodiscard]] const T1 & operator*() const
153 {
154 return get();
155 }
156
157 [[nodiscard]] const Error & error() const
158 {
159 // NOTE: std::get also performs the check of what is stored inside the
160 // variant but it throws std::bad_variant_access which doesn't implement
161 // QException so this exception is not representable inside QFuture
162 // in Qt5. Due to this for Qt5 also performing another check and using
163 // another exception type
164#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
165 if (Q_UNLIKELY(isValid())) {
166 throw RuntimeError{ErrorString{
167 "Detected attempt to get error from non-empty Result"}};
168 }
169#endif
170
171 return std::get<Error>(m_valueOrError);
172 }
173
174 [[nodiscard]] Error & error()
175 {
176 // NOTE: std::get also performs the check of what is stored inside the
177 // variant but it throws std::bad_variant_access which doesn't implement
178 // QException so this exception is not representable inside QFuture
179 // in Qt5. Due to this for Qt5 also performing another check and using
180 // another exception type
181#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
182 if (Q_UNLIKELY(isValid())) {
183 throw RuntimeError{ErrorString{
184 "Detected attempt to get error from non-empty Result"}};
185 }
186#endif
187
188 return std::get<Error>(m_valueOrError);
189 }
190
191private:
192 std::variant<ValueType, Error> m_valueOrError;
193};
194
195} // namespace quentier
The Result template class represents the bare bones result monad implementation which either contains...
Definition Result.h:38
bool isValid() const noexcept
Definition Result.h:87