libquentier  0.8.0
The library for rich desktop clients of Evernote service
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 
27 namespace quentier {
28 
29 template <
30  class ValueType, class ErrorType,
31  typename =
32  typename std::enable_if_t<!std::is_void_v<std::decay_t<ErrorType>>>>
33 class Result
34 {
35 private:
36  template <typename T>
37  struct ValueWrapper
38  {
39  T value;
40  };
41 
42  using ValueWrapperInnerType = std::conditional_t<
43  std::is_void_v<std::decay_t<ValueType>>, std::nullptr_t,
44  std::decay_t<ValueType>>;
45 
46 public:
47  template <
48  typename T1 = ValueType,
49  typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
50  nullptr>
51  explicit Result(T1 t) :
52  m_valueOrError{ValueWrapper<std::decay_t<ValueType>>{std::move(t)}}
53  {}
54 
55  template <
56  typename T1 = ValueType,
57  typename std::enable_if_t<std::is_void_v<std::decay_t<T1>>> * = nullptr>
58  explicit Result() : m_valueOrError{ValueWrapper<std::nullptr_t>{}}
59  {}
60 
61  explicit Result(ErrorType error) : m_valueOrError{std::move(error)} {}
62 
63  Result(const Result<ValueType, ErrorType> & other) :
64  m_valueOrError{other.m_valueOrError}
65  {}
66 
68  m_valueOrError{std::move(other.m_valueOrError)}
69  {}
70 
71  Result & operator=(const Result<ValueType, ErrorType> & other)
72  {
73  if (this != &other) {
74  m_valueOrError = other.m_valueOrError;
75  }
76 
77  return *this;
78  }
79 
80  Result & operator=(Result<ValueType, ErrorType> && other)
81  {
82  if (this != &other) {
83  m_valueOrError = std::move(other.m_valueOrError);
84  }
85 
86  return *this;
87  }
88 
92  [[nodiscard]] bool isValid() const noexcept
93  {
94  return std::holds_alternative<ValueWrapper<ValueWrapperInnerType>>(
95  m_valueOrError);
96  }
97 
98  operator bool() const noexcept
99  {
100  return isValid();
101  }
102 
103  template <
104  typename T1 = ValueType,
105  typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
106  nullptr>
107  [[nodiscard]] T1 & get()
108  {
109  // NOTE: std::get also performs the check of what is stored inside the
110  // variant but it throws std::bad_variant_access which doesn't implement
111  // QException so this exception is not representable inside QFuture
112  // in Qt5. Due to this for Qt5 also performing another check and using
113  // another exception type
114 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
115  if (Q_UNLIKELY(!isValid())) {
116  throw RuntimeError{
117  ErrorString{"Detected attempt to get value from empty Result"}};
118  }
119 #endif
120 
121  return std::get<ValueWrapper<std::decay_t<ValueType>>>(m_valueOrError)
122  .value;
123  }
124 
125  template <
126  typename T1 = ValueType,
127  typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
128  nullptr>
129  [[nodiscard]] const T1 & get() const
130  {
131  // NOTE: std::get also performs the check of what is stored inside the
132  // variant but it throws std::bad_variant_access which doesn't implement
133  // QException so this exception is not representable inside QFuture
134  // in Qt5. Due to this for Qt5 also performing another check and using
135  // another exception type
136 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
137  if (Q_UNLIKELY(!isValid())) {
138  throw RuntimeError{
139  ErrorString{"Detected attempt to get value from empty Result"}};
140  }
141 #endif
142 
143  return std::get<ValueWrapper<std::decay_t<ValueType>>>(m_valueOrError)
144  .value;
145  }
146 
147  template <
148  typename T1 = ValueType,
149  typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
150  nullptr>
151  [[nodiscard]] T1 & operator*()
152  {
153  return get();
154  }
155 
156  template <
157  typename T1 = ValueType,
158  typename std::enable_if_t<!std::is_void_v<std::decay_t<T1>>> * =
159  nullptr>
160  [[nodiscard]] const T1 & operator*() const
161  {
162  return get();
163  }
164 
165  [[nodiscard]] const ErrorType & error() const
166  {
167  // NOTE: std::get also performs the check of what is stored inside the
168  // variant but it throws std::bad_variant_access which doesn't implement
169  // QException so this exception is not representable inside QFuture
170  // in Qt5. Due to this for Qt5 also performing another check and using
171  // another exception type
172 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
173  if (Q_UNLIKELY(isValid())) {
174  throw RuntimeError{ErrorString{
175  "Detected attempt to get error from non-empty Result"}};
176  }
177 #endif
178 
179  return std::get<ErrorType>(m_valueOrError);
180  }
181 
182  [[nodiscard]] ErrorType & error()
183  {
184  // NOTE: std::get also performs the check of what is stored inside the
185  // variant but it throws std::bad_variant_access which doesn't implement
186  // QException so this exception is not representable inside QFuture
187  // in Qt5. Due to this for Qt5 also performing another check and using
188  // another exception type
189 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
190  if (Q_UNLIKELY(isValid())) {
191  throw RuntimeError{ErrorString{
192  "Detected attempt to get error from non-empty Result"}};
193  }
194 #endif
195 
196  return std::get<ErrorType>(m_valueOrError);
197  }
198 
199 private:
200  std::variant<ValueWrapper<ValueWrapperInnerType>, ErrorType> m_valueOrError;
201 };
202 
203 } // namespace quentier
bool isValid() const noexcept
Definition: Result.h:92
Definition: Result.h:33