Diag-Client-Lib
result.h
Go to the documentation of this file.
1 /* Diagnostic Client library
2  * Copyright (C) 2024 Avijit Dey
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 */
8 #ifndef DIAG_CLIENT_LIB_LIB_PLATFORM_CORE_RESULT_H_
9 #define DIAG_CLIENT_LIB_LIB_PLATFORM_CORE_RESULT_H_
10 
11 #include <optional>
12 #include <type_traits>
13 #include <utility>
14 #include <variant>
15 
17 
18 namespace core_type {
19 
28 template<typename T, typename E = ErrorCode>
29 class Result final {
30  public:
34  using value_type = T;
35 
39  using error_type = E;
40 
48  static Result FromValue(T &t) noexcept { return Result{t}; }
49 
57  static Result FromValue(T &&t) noexcept { return Result{std::move(t)}; }
58 
71  template<typename... Args>
72  static Result FromValue(Args &&...args) noexcept {
73  return Result{std::forward<Args>(args)...};
74  }
75 
83  static Result FromError(const E &e) noexcept { return Result{e}; }
84 
92  static Result FromError(E &&e) noexcept { return Result{std::move(e)}; }
93 
106  template<typename... Args>
107  static Result FromError(Args &&...args) noexcept {
108  return Result{std::forward<Args>(args)...};
109  }
110 
116  constexpr explicit Result(const T &t) noexcept : storage_{t} {}
117 
123  constexpr explicit Result(T &&t) noexcept : storage_{std::move(t)} {}
124 
130  constexpr explicit Result(const E &e) noexcept : storage_{e} {}
131 
137  constexpr explicit Result(E &&e) noexcept : storage_{std::move(e)} {}
138 
144  Result(const Result &other) = default;
145 
153  Result &operator=(const Result &other) = default;
154 
160  Result(Result &&other) noexcept(
161  std::is_nothrow_move_constructible<T>::value &&std::is_nothrow_move_constructible<E>::value) = default;
162 
170  Result &operator=(Result &&other) noexcept(
171  std::is_nothrow_move_constructible<T>::value &&std::is_nothrow_move_assignable<T>::value
172  &&std::is_nothrow_move_constructible<E>::value &&std::is_nothrow_move_assignable<E>::value) = default;
173 
177  ~Result() noexcept = default;
178 
186  template<typename... Args>
187  void EmplaceValue(Args &&...args) noexcept {
188  storage_.template emplace<value_type>(std::forward<Args>(args)...);
189  }
190 
198  template<typename... Args>
199  void EmplaceError(Args &&...args) noexcept {
200  storage_.template emplace<error_type>(std::forward<Args>(args)...);
201  }
202 
208  bool HasValue() const noexcept { return std::holds_alternative<value_type>(storage_); }
209 
215  explicit operator bool() const noexcept { return HasValue(); }
216 
223  const T &operator*() const &noexcept { return std::get<value_type>(storage_); }
224 
231  T &&operator*() &&noexcept { return std::move(std::get<value_type>(storage_)); }
232 
239  const T *operator->() const noexcept { return std::get_if<value_type>(storage_); }
240 
247  const T &Value() const &noexcept { return std::get<value_type>(storage_); }
248 
255  T &&Value() &&noexcept { return std::move(std::get<value_type>(storage_)); }
256 
263  const E &Error() const &noexcept { return std::get<error_type>(storage_); }
264 
271  E &&Error() &&noexcept { return std::move(std::get<error_type>(storage_)); }
272 
278  std::optional<T> Ok() const &noexcept {
279  std::optional<T> opt_val{};
280  if (HasValue()) { opt_val.emplace(Value()); }
281  return opt_val;
282  }
283 
289  std::optional<T> Ok() &&noexcept {
290  std::optional<T> opt_val{};
291  if (HasValue()) { opt_val.emplace(std::move(Value())); }
292  return opt_val;
293  }
294 
300  std::optional<E> Err() const &noexcept {
301  std::optional<E> opt_err{};
302  if (!HasValue()) { opt_err.emplace(Error()); }
303  return opt_err;
304  }
305 
311  std::optional<E> Err() &&noexcept {
312  std::optional<E> opt_err{};
313  if (!HasValue()) { opt_err.emplace(std::move(Error())); }
314  return opt_err;
315  }
316 
327  template<typename F, typename T2 = typename std::invoke_result_t<F, T>>
328  Result<T2, E> AndThen(F &&fn) &&noexcept {
329  return HasValue() ? Result<T2, E>{fn(std::move(*this).Value())} : Result<T2, E>{*this};
330  }
331 
342  template<typename F, typename E2 = std::invoke_result_t<F, E>>
344  return HasValue() ? Result<T, E2>{std::move(*this).Value()} : Result<T, E2>{fn(std::move(*this).Error())};
345  }
346 
357  template<typename F>
358  Result OrElse(F &&fn) &&noexcept {
359  return HasValue() ? Result{std::move(*this)} : Result{fn(std::move(*this).Error())};
360  }
361 
372  template<typename U>
373  T ValueOr(U &&defaultValue) const &noexcept {
374  return HasValue() ? Result{*this} : static_cast<T>(defaultValue);
375  }
376 
387  template<typename U>
388  T ValueOr(U &&defaultValue) &&noexcept {
389  return HasValue() ? Result{std::move(*this)} : static_cast<T>(defaultValue);
390  }
391 
402  template<typename G>
403  E ErrorOr(G &&defaultError) const &noexcept {
404  return !HasValue() ? Result{*this} : static_cast<E>(defaultError);
405  }
406 
417  template<typename G>
418  E ErrorOr(G &&defaultError) &&noexcept {
419  return !HasValue() ? Result{std::move(*this)} : static_cast<E>(defaultError);
420  }
421 
434  template<typename F>
435  T Resolve(F &&f) const {
436  return HasValue() ? Result{*this} : f(Error());
437  }
438 
439  private:
443  std::variant<T, E> storage_;
444 };
445 
452 template<typename E>
453 class Result<void, E> final {
454  public:
458  using value_type = void;
459 
463  using error_type = E;
464 
470  static Result FromValue() noexcept { return Result{}; }
471 
479  static Result FromError(const E &e) noexcept { return Result{e}; }
480 
488  static Result FromError(E &&e) noexcept { return Result{std::move(e)}; }
489 
502  template<typename... Args>
503  static Result FromError(Args &&...args) noexcept {
504  return Result{std::forward<Args>(args)...};
505  }
506 
510  constexpr explicit Result() noexcept : storage_{empty_value{}} {}
511 
517  constexpr explicit Result(const E &e) noexcept : storage_{e} {}
518 
524  constexpr explicit Result(E &&e) noexcept : storage_{std::move(e)} {}
525 
531  Result(const Result &other) = default;
532 
540  Result &operator=(const Result &other) = default;
541 
547  Result(Result &&other) noexcept(std::is_nothrow_move_constructible<E>::value) = default;
548 
556  Result &operator=(Result &&other) noexcept(
557  std::is_nothrow_move_constructible<E>::value &&std::is_nothrow_move_assignable<E>::value) = default;
558 
562  ~Result() noexcept { static_assert(std::is_trivially_destructible<E>::value); }
563 
567  void EmplaceValue() noexcept { storage_.EmplaceValue(empty_value{}); }
568 
576  template<typename... Args>
577  void EmplaceError(Args &&...args) noexcept {
578  storage_.EmplaceError(std::forward<Args>(args)...);
579  }
580 
586  bool HasValue() const noexcept { return storage_.HasValue(); }
587 
593  explicit operator bool() const noexcept { return HasValue(); }
594 
601  const E &Error() const &noexcept { return storage_.Error(); }
602 
609  E &&Error() &&noexcept { return std::move(storage_.Error()); }
610 
616  std::optional<E> Err() const &noexcept {
617  std::optional<E> opt_err{};
618  if (!HasValue()) { opt_err.emplace(Error()); }
619  return opt_err;
620  }
621 
627  std::optional<E> Err() &&noexcept {
628  std::optional<E> opt_err{};
629  if (!HasValue()) { opt_err.emplace(std::move(Error())); }
630  return opt_err;
631  }
632 
643  template<typename F, typename E2 = std::invoke_result_t<F, E>>
645  return HasValue() ? Result<void, E2>{} : Result<void, E2>{fn(Error())};
646  }
647 
658  template<typename F, typename E2 = std::invoke_result_t<F, E>>
660  return HasValue() ? Result<void, E2>{} : Result<void, E2>{fn(Error())};
661  }
662 
673  template<typename F>
674  Result AndThen(F &&fn) &&noexcept {
675  if (HasValue()) { fn(); }
676  return Result{std::move(*this)};
677  }
678 
689  template<typename F>
690  Result OrElse(F &&fn) &&noexcept {
691  return HasValue() ? Result{std::move(*this)} : Result{fn(Error())};
692  }
693 
704  template<typename G>
705  E ErrorOr(G &&defaultError) const &noexcept {
706  return !HasValue() ? Result{*this} : static_cast<E>(defaultError);
707  }
708 
719  template<typename G>
720  E ErrorOr(G &&defaultError) &&noexcept {
721  return !HasValue() ? Result{std::move(*this)} : static_cast<E>(defaultError);
722  }
723 
735  template<typename F>
736  void Resolve(F &&f) const {
737  f(Error());
738  }
739 
740  private:
744  struct empty_value {};
745 
750 };
751 
752 } // namespace core_type
753 
754 #endif // DIAG_CLIENT_LIB_LIB_PLATFORM_CORE_RESULT_H_
static Result FromError(E &&e) noexcept
Build a new Result from the specified error (given as rvalue)
Definition: result.h:488
Result & operator=(const Result &other)=default
Copy-assign another Result to this instance.
constexpr Result() noexcept
Construct a new Result with a "void" value.
Definition: result.h:510
Result< void, E2 > CheckError(F &&fn)
Returns the result of the given function on the contained value if it exists; otherwise,...
Definition: result.h:659
static Result FromValue() noexcept
Build a new Result with "void" as value.
Definition: result.h:470
void EmplaceError(Args &&...args) noexcept
Put a new error into this instance, constructed in-place from the given arguments.
Definition: result.h:577
E error_type
Type alias for the type E of errors.
Definition: result.h:463
const E & Error() const &noexcept
Access the contained error.
Definition: result.h:601
Result AndThen(F &&fn) &&noexcept
Returns the result of the given function on the contained value if it exists; otherwise,...
Definition: result.h:674
Result OrElse(F &&fn) &&noexcept
Returns the result itself if it contains a value; otherwise, returns the result of the given function...
Definition: result.h:690
void value_type
Type alias for the type T of values, always "void" for this specialization.
Definition: result.h:458
E && Error() &&noexcept
Access the contained error.
Definition: result.h:609
Result< void, E2 > MapError(F &&fn)
Returns the result of the given function on the contained value if it exists; otherwise,...
Definition: result.h:644
bool HasValue() const noexcept
Check whether *this contains a value.
Definition: result.h:586
static Result FromError(const E &e) noexcept
Build a new Result from the specified error (given as lvalue)
Definition: result.h:479
Result(Result &&other) noexcept(std::is_nothrow_move_constructible< E >::value)=default
Move-construct a new Result from another instance.
Result & operator=(Result &&other) noexcept(std::is_nothrow_move_constructible< E >::value &&std::is_nothrow_move_assignable< E >::value)=default
Move-assign another Result to this instance.
E ErrorOr(G &&defaultError) &&noexcept
Return the contained error or the given default error.
Definition: result.h:720
constexpr Result(const E &e) noexcept
Construct a new Result from the specified error (given as lvalue)
Definition: result.h:517
E ErrorOr(G &&defaultError) const &noexcept
Return the contained error or the given default error.
Definition: result.h:705
static Result FromError(Args &&...args) noexcept
Build a new Result from an error that is constructed in-place from the given arguments.
Definition: result.h:503
void Resolve(F &&f) const
Do nothing or call a function.
Definition: result.h:736
std::optional< E > Err() &&noexcept
Return the contained error as an Optional.
Definition: result.h:627
std::optional< E > Err() const &noexcept
Return the contained error as an Optional.
Definition: result.h:616
Result< empty_value, E > storage_
Storage to contain an empty value or error of type E.
Definition: result.h:749
void EmplaceValue() noexcept
Put a new value into this instance, constructed in-place from the given arguments.
Definition: result.h:567
~Result() noexcept
Destruct an instance of Result.
Definition: result.h:562
Result(const Result &other)=default
Copy-construct a new Result from another instance.
constexpr Result(E &&e) noexcept
Construct a new Result from the specified error (given as rvalue)
Definition: result.h:524
Class type to contains a value (of type ValueType), or an error (of type ErrorType)
Definition: result.h:29
constexpr Result(const T &t) noexcept
Construct a new Result from the specified value (given as lvalue)
Definition: result.h:116
const T & operator*() const &noexcept
Access the contained value.
Definition: result.h:223
constexpr Result(T &&t) noexcept
Construct a new Result from the specified value (given as rvalue)
Definition: result.h:123
Result & operator=(Result &&other) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_move_assignable< T >::value &&std::is_nothrow_move_constructible< E >::value &&std::is_nothrow_move_assignable< E >::value)=default
Move-assign another Result to this instance.
static Result FromValue(T &&t) noexcept
Build a new Result from the specified value (given as rvalue)
Definition: result.h:57
std::optional< E > Err() const &noexcept
Return the contained error as an Optional.
Definition: result.h:300
std::optional< T > Ok() const &noexcept
Return the contained value as an Optional.
Definition: result.h:278
T ValueOr(U &&defaultValue) const &noexcept
Return the contained value or the given default value.
Definition: result.h:373
void EmplaceError(Args &&...args) noexcept
Put a new error into this instance, constructed in-place from the given arguments.
Definition: result.h:199
Result< T, E2 > MapError(F &&fn)
Returns the result of the given function on the contained value if it exists; otherwise,...
Definition: result.h:343
E ErrorOr(G &&defaultError) &&noexcept
Return the contained error or the given default error.
Definition: result.h:418
std::variant< T, E > storage_
Storage to contain value of type T or error of type E.
Definition: result.h:443
std::optional< T > Ok() &&noexcept
Return the contained value as an Optional.
Definition: result.h:289
Result(const Result &other)=default
Copy-construct a new Result from another instance.
Result(Result &&other) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_move_constructible< E >::value)=default
Move-construct a new Result from another instance.
Result & operator=(const Result &other)=default
Copy-assign another Result to this instance.
const T & Value() const &noexcept
Access the contained value.
Definition: result.h:247
static Result FromError(const E &e) noexcept
Build a new Result from the specified error (given as lvalue)
Definition: result.h:83
const E & Error() const &noexcept
Access the contained error.
Definition: result.h:263
static Result FromError(Args &&...args) noexcept
Build a new Result from an error that is constructed in-place from the given arguments.
Definition: result.h:107
E ErrorOr(G &&defaultError) const &noexcept
Return the contained error or the given default error.
Definition: result.h:403
E && Error() &&noexcept
Access the contained error.
Definition: result.h:271
T Resolve(F &&f) const
Return the contained value or return the result of a function call.
Definition: result.h:435
constexpr Result(const E &e) noexcept
Construct a new Result from the specified error (given as lvalue)
Definition: result.h:130
bool HasValue() const noexcept
Check whether *this contains a value.
Definition: result.h:208
Result< T2, E > AndThen(F &&fn) &&noexcept
Returns the result of the given function on the contained value if it exists; otherwise,...
Definition: result.h:328
~Result() noexcept=default
Destruct an instance of Result.
T && Value() &&noexcept
Access the contained value.
Definition: result.h:255
T && operator*() &&noexcept
Access the contained value.
Definition: result.h:231
Result OrElse(F &&fn) &&noexcept
Returns the result itself if it contains a value; otherwise, returns the result of the given function...
Definition: result.h:358
const T * operator->() const noexcept
Access the contained value.
Definition: result.h:239
T ValueOr(U &&defaultValue) &&noexcept
Return the contained value or the given default value.
Definition: result.h:388
E error_type
Type alias for the type E of errors.
Definition: result.h:39
constexpr Result(E &&e) noexcept
Construct a new Result from the specified error (given as rvalue)
Definition: result.h:137
T value_type
Type alias for the type T of values.
Definition: result.h:34
static Result FromValue(Args &&...args) noexcept
Build a new Result from a value that is constructed in-place from the given arguments.
Definition: result.h:72
static Result FromError(E &&e) noexcept
Build a new Result from the specified error (given as rvalue)
Definition: result.h:92
void EmplaceValue(Args &&...args) noexcept
Put a new value into this instance, constructed in-place from the given arguments.
Definition: result.h:187
static Result FromValue(T &t) noexcept
Build a new Result from the specified value (given as lvalue)
Definition: result.h:48
std::optional< E > Err() &&noexcept
Return the contained error as an Optional.
Definition: result.h:311