knowL: Knowledge Libraries
Loading...
Searching...
No Matches
ReturnValue.h
1#pragma once
2
3#include <type_traits>
4
5#include <knowCore/Forward.h>
6
7#include "Global.h"
8#include "Logging.h"
9#include "NamedType.h"
10
11template<typename _T_>
12knowCore::ReturnValue<_T_> kCrvSuccess(const _T_& _t);
13
14template<typename>
15class QSharedPointer;
16
17namespace knowCore
18{
19 template<template<typename> class _RV_>
20 struct FollowReturnValuePattern : public std::false_type
21 {};
27 template<typename _T_>
29 {
30 friend knowCore::ReturnValue<_T_> kCrvSuccess<_T_>(const _T_& _t);
31 private:
32 explicit ReturnValue(const _T_& _value)
33 : m_success(true), m_value(_value)
34 {}
35 public:
36 ReturnValue() : m_success(false), m_message("Unset return value.")
37 {}
38 ReturnValue(const ReturnValue& _rhs) : m_success(_rhs.m_success), m_value(_rhs.m_value), m_message(_rhs.m_message)
39 {
40 KNOWCORE_ASSERT(m_message != "Unset return value.");
41 }
42 ReturnValue& operator=(const ReturnValue& _rhs)
43 {
44 m_success = _rhs.m_success; m_value = _rhs.m_value; m_message = _rhs.m_message;
45 KNOWCORE_ASSERT(m_message != "Unset return value.");
46 return *this;
47 }
48 template<typename _TOther_, template<typename> class _RV_, std::enable_if_t<FollowReturnValuePattern<_RV_>::value and std::is_convertible_v<_TOther_, _T_>, bool> = true>
49 ReturnValue(const _RV_<_TOther_>& _rhs) : m_success(_rhs.success()), m_value(_rhs.value()), m_message(_rhs.message())
50 {
51 }
52 template<typename _TOther_>
53 ReturnValue(const ReturnValue<_TOther_>& _rhs, std::enable_if_t<std::is_convertible_v<_TOther_, _T_>>* = nullptr)
54 : m_success(_rhs.success()), m_value(_rhs.value()), m_message(_rhs.message())
55 {}
56 template<typename _TOther_>
57 explicit ReturnValue(const ReturnValue<_TOther_>& _rhs, std::enable_if_t<details::is_instance_v<_T_, QSharedPointer> and std::is_same_v<_TOther_, _TOther_>>* = nullptr) : m_success(_rhs.success()), m_value(_rhs.value()), m_message(_rhs.message())
58 {}
59 ReturnValue(const ReturnValueError& _rve) : m_success(false), m_value(), m_message(_rve.value())
60 {}
61 bool success() const { return m_success; }
62 const _T_& value() const { return m_value; }
63 const _T_& expectSuccess() const { if(not m_success) { KNOWCORE_LOG_FATAL("Success was expected but got error '{}'", m_message); } return m_value; }
64 const QString& message() const { return m_message; }
65 template <size_t I>
66 auto const& get() const & {
67 if constexpr (I == 0) return m_success;
68 else if constexpr (I == 1) return m_value;
69 else if constexpr (I == 2) return m_message;
70 }
71 template <size_t I>
72 auto && get() && {
73 if constexpr (I == 0) return std::move(m_success);
74 else if constexpr (I == 1) return std::move(m_value);
75 else if constexpr (I == 2) return std::move(m_message);
76 }
77 ReturnValue<void> discardValue() const;
78 private:
79 bool m_success;
80 _T_ m_value;
81 QString m_message;
82 };
83 template<>
84 class ReturnValue<void>
85 {
86 private:
87 explicit ReturnValue(void*)
88 : m_success(true)
89 {}
90 public:
91 ReturnValue() : m_success(false), m_message("Unset return void.")
92 {}
93 ReturnValue(const ReturnValue& _rhs) : m_success(_rhs.m_success), m_message(_rhs.m_message)
94 {
95 KNOWCORE_ASSERT(m_message != "Unset return void.");
96 }
97 template<typename _T_>
98 Q_DECL_DEPRECATED_X("Use discardValue() instead") ReturnValue(const ReturnValue<_T_>& _rhs): m_success(_rhs.success()), m_message(_rhs.message())
99 {
100 // TODO add static assert to trigger an error if used
101 KNOWCORE_ASSERT(m_message != "Unset return void.");
102 }
103 ReturnValue& operator=(const ReturnValue& _rhs)
104 {
105 m_success = _rhs.m_success; m_message = _rhs.m_message;
106 KNOWCORE_ASSERT(m_message != "Unset return value.");
107 return *this;
108 }
109 ReturnValue(const ReturnValueError& _rve) : m_success(false), m_message(_rve.value())
110 {}
111 static ReturnValue<void> createSuccess() { return ReturnValue(nullptr); }
112 bool success() const { return m_success; }
113 void expectSuccess() const { if(not m_success) { KNOWCORE_LOG_FATAL("Success was expected but got error '{}'", m_message); } }
114 const QString& message() const { return m_message; }
115 template <size_t I>
116 auto const& get() const & {
117 if constexpr (I == 0) return m_success;
118 else if constexpr (I == 1) return message();
119 }
120 template <size_t I>
121 auto && get() && {
122 if constexpr (I == 0) return m_success;
123 else if constexpr (I == 1) return message();
124 }
125 private:
126 bool m_success;
127 QString m_message;
128 };
129 template<typename _T_>
131 {
132 return m_success ? ReturnValue<void>::createSuccess() : ReturnValue<void>(ReturnValueError(m_message));
133 }
134 template<>
135 class ReturnValue<QString>
136 {
137 public:
138 ReturnValue(const QString& _message_value) : m_success(true), m_message_value(_message_value)
139 {
140 }
141 ReturnValue(const ReturnValueError& _rve) : m_success(false), m_message_value(_rve.value())
142 {}
143 bool success() const { return m_success; }
144 QString value() const { return m_success ? m_message_value : QString(); }
145 QString expectSuccess() const { if(Q_UNLIKELY(not m_success)) { KNOWCORE_LOG_FATAL("Success was expected but got error '{}'", m_message_value); } return m_message_value; }
146 QString message() const { return m_success ? QString() : m_message_value; }
147 template <size_t I>
148 auto const get() const & {
149 if constexpr (I == 0) return m_success;
150 else if constexpr (I == 1) return value();
151 else if constexpr (I == 2) return message();
152 }
153 private:
154 bool m_success;
155 QString m_message_value;
156 };
157}
158
159template<typename _T_>
160struct fmt::formatter<knowCore::ReturnValue<_T_>> : public fmt::formatter<_T_>
161{
162 template <typename FormatContext>
163 auto format(knowCore::ReturnValue<_T_> const& p, FormatContext& ctx) -> decltype(ctx.out())
164 {
165 if(p.success())
166 {
167 return fmt::formatter<_T_>::format(p.value(), ctx);
168 } else {
169 return format_to(ctx.out(), "failure({})", p.message());
170 }
171 }
172};
173
174KNOWCORE_CORE_DECLARE_FORMATTER(knowCore::ReturnVoid)
175{
176 if(p.success()) return forward("success()", ctx);
177 else return format(ctx.out(), "failure({})", p.message());
178}
179
180namespace std {
181 template <typename _T_> struct tuple_size<knowCore::ReturnValue<_T_>> : std::integral_constant<size_t, 3> { };
182
183 template <typename _T_> struct tuple_element<0, knowCore::ReturnValue<_T_>> { using type = bool; };
184 template <typename _T_> struct tuple_element<1, knowCore::ReturnValue<_T_>> { using type = _T_; };
185 template <typename _T_> struct tuple_element<2, knowCore::ReturnValue<_T_>> { using type = QString; };
186
187 template <> struct tuple_size<knowCore::ReturnVoid> : std::integral_constant<size_t, 2> { };
188
189 template <> struct tuple_element<0, knowCore::ReturnVoid> { using type = bool; };
190 template <> struct tuple_element<1, knowCore::ReturnVoid> { using type = QString; };
191}
192
197template<typename _T_>
198inline knowCore::ReturnValue<_T_> kCrvSuccess(const _T_& _t)
199{
201}
202
207inline knowCore::ReturnVoid kCrvSuccess()
208{
209 return knowCore::ReturnVoid::createSuccess();
210}
211
215template<typename _T_>
216inline knowCore::ReturnValue<_T_> kCrvReturnResult(const _T_& _t)
217{
218 return kCrvSuccess(_t);
219}
220
221template<typename _T_>
222const inline knowCore::ReturnValue<_T_>& kCrvReturnResult(const knowCore::ReturnValue<_T_>& _t)
223{
224 return _t;
225}
226
236template<typename... _Args_>
237inline knowCore::ReturnValueError kCrvError(const QString& _str, _Args_... _args)
238{
239 return knowCore::ReturnValueError(clog_qt::qformat(_str, _args...));
240}
241
251#define kCrvLogError(...) \
252[&]() { \
253 QString err = clog_qt::qformat(__VA_ARGS__); \
254 KNOWCORE_LOG_ERROR(err.toStdString()); \
255 return knowCore::ReturnValueError(err); \
256}();
257
258template<typename _T_>
259bool operator==(const knowCore::ReturnValue<_T_>& _lhs, const _T_& _rhs)
260{
261 return _lhs.success() and _lhs.value() == _rhs;
262}
263
264namespace knowCore::details
265{
266 template<typename _T_, typename... _Args_>
267 struct CrvCond
268 {
269 ReturnValue<_T_> operator()(bool _cond, const _T_& _value, _Args_... _args)
270 {
271 if(_cond)
272 {
273 return kCrvSuccess(_value);
274 } else {
275 return kCrvError(_args...);
276 }
277 }
278 };
279 template<typename... _Args_>
280 struct CrvCond<void, _Args_...>
281 {
282 ReturnVoid operator()(bool _cond, _Args_... _args)
283 {
284 if(_cond)
285 {
286 return kCrvSuccess();
287 } else {
288 return kCrvError(_args...);
289 }
290 }
291 };
292}
293
294template<typename _T_, typename... _Args_>
295inline knowCore::ReturnValue<_T_> kCrvCond(bool _cond, const _T_& _value, _Args_... _args)
296{
297 return knowCore::details::CrvCond<_T_, _Args_...>()(_cond, _value, _args...);
298}
299
300template<typename _T_, typename... _Args_>
301inline knowCore::ReturnValue<_T_> kCrvCond(bool _cond, _Args_... _args)
302{
303 static_assert(std::is_same_v<_T_, void>, "For non void, a value must be given");
304 return knowCore::details::CrvCond<_T_, _Args_...>()(_cond, _args...);
305}
306
311template<typename _TA_, typename _TRV_>
312inline knowCore::ReturnVoid kCrvTryAssign(_TA_* _value, const knowCore::ReturnValue<_TRV_>& _return_value, std::enable_if_t<std::is_convertible_v<_TRV_, _TA_>>* = nullptr)
313{
314 auto const [success, value, message] = _return_value;
315 if(success)
316 {
317 *_value = value;
318 return kCrvSuccess();
319 } else {
320 return kCrvError(message);
321 }
322}
323
324
325#define __KNOWCORE_KCRV_ERROR_2(_ERR_MSG_, _MSG_) _MSG_, _ERR_MSG_
326#define __KNOWCORE_KCRV_ERROR_1(_ERR_MSG_) _ERR_MSG_
327
328#define __KNOWCORE_KCRV_ERROR_CHOOSER(M, ...) __KNOWCORE_GET_2ND_ARG(__VA_OPT__(,) __VA_ARGS__ , __KNOWCORE_KCRV_ERROR_2, __KNOWCORE_KCRV_ERROR_1, )
329
330#define __KNOWCORE_KCRV_ERROR(...) __KNOWCORE_KCRV_ERROR_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
331
332namespace knowCore::details
333{
338 inline knowCore::ReturnValueError kCrvErrorKRVTA(const QString& _err)
339 {
340 return kCrvError(_err);
341 }
346 template<typename... _TArgs_>
347 inline knowCore::ReturnValueError kCrvErrorKRVTA(const QString& _err, const char* _format, const _TArgs_&... _args)
348 {
349 return kCrvError(_format, _args..., _err);
350 }
351}
352
353#define __KNOWCORE_EMPTY_ACTION {}
354
365#define KNOWCORE_RETURN_VALUE_TRY_ASSIGN_DO(_VARIABLE_, _EXPR_, _ACTION_, ...) \
366 { \
367 auto const [__krv__success__ ## __LINE__, __krv__value__ ## __LINE__, \
368 __krv__message__ ## __LINE__ ] = (_EXPR_); \
369 if(__krv__success__ ## __LINE__) { _VARIABLE_ = __krv__value__ ## __LINE__; } \
370 else { _ACTION_; return knowCore::details::kCrvErrorKRVTA(__krv__message__ ## __LINE__ __VA_OPT__(,) __VA_ARGS__); } \
371 }
372
383#define KNOWCORE_RETURN_VALUE_TRY_ASSIGN(_VARIABLE_, _EXPR_, ...) \
384 KNOWCORE_RETURN_VALUE_TRY_ASSIGN_DO(_VARIABLE_, (_EXPR_), __KNOWCORE_EMPTY_ACTION, __VA_ARGS__)
385
397#define KNOWCORE_RETURN_VALUE_TRY_DO(_VARIABLE_, _EXPR_, _ACTION_, ...) \
398 std::remove_const_t<std::remove_reference_t<decltype((_EXPR_).value())>> _VARIABLE_; \
399 KNOWCORE_RETURN_VALUE_TRY_ASSIGN_DO(_VARIABLE_, (_EXPR_), _ACTION_ __VA_OPT__(,) __VA_ARGS__)
400
412#define KNOWCORE_RETURN_VALUE_TRY(_VARIABLE_, _EXPR_, ...) \
413 KNOWCORE_RETURN_VALUE_TRY_DO(_VARIABLE_, (_EXPR_), __KNOWCORE_EMPTY_ACTION __VA_OPT__(,) __VA_ARGS__)
414
426#define KNOWCORE_RETURN_VALUE_TRY_VOID_DO(_EXPR_, _ACTION_, ...) \
427 { \
428 auto const [__krv__success__ ## __LINE__, __krv__message__ ## __LINE__ ] = (_EXPR_); \
429 if(not __krv__success__ ## __LINE__) { _ACTION_; return kCrvError(__KNOWCORE_KCRV_ERROR(__krv__message__ ## __LINE__) __VA_OPT__(,) __VA_ARGS__ ); } \
430 }
431
443#define KNOWCORE_RETURN_VALUE_TRY_VOID(_EXPR_, ...) \
444 KNOWCORE_RETURN_VALUE_TRY_VOID_DO((_EXPR_), __KNOWCORE_EMPTY_ACTION, __VA_ARGS__)
445
449#define KNOWCORE_RETURN_VALUE_CHECK(_CHECK_, _ERROR_MSG_, ...) \
450 if(not (_CHECK_)) { return kCrvError(_ERROR_MSG_ __VA_OPT__(,) __VA_ARGS__); }
Definition Forward.h:4
Definition NamedType.h:40
Definition ReturnValue.h:85
Definition ReturnValue.h:29
friend knowCore::ReturnValue< _T_ > kCrvSuccess(const _T_ &_t)
Definition ReturnValue.h:198
Definition ReturnValue.h:21
Definition ReturnValue.h:268