Spicy
result.h
1 // Copyright (c) 2020-2021 by the Zeek Project. See LICENSE for details.
2 
3 #pragma once
4 
5 #include <optional>
6 #include <ostream>
7 #include <string>
8 #include <utility>
9 #include <variant>
10 
11 #include <hilti/rt/exception.h>
12 
13 namespace hilti::rt {
14 
15 namespace result {
16 
18 class Error {
19 public:
20  Error(std::string description = "<no description>", std::string context = "")
21  : _description(std::move(description)), _context(std::move(context)) {}
22  const auto& description() const { return _description; }
23  const auto& context() const { return _context; }
24  operator std::string() const { return _description; }
25  operator std::string_view() const { return _description; }
26 
27 private:
28  std::string _description;
29  std::string _context;
30 };
31 
32 inline std::ostream& operator<<(std::ostream& out, const Error& error) {
33  out << error.description();
34  return out;
35 }
36 
37 inline bool operator==(const Error& a, const Error& b) { return a.description() == b.description(); }
38 inline bool operator!=(const Error& a, const Error& b) { return ! (a == b); }
39 
41 class NoResult : public RuntimeError {
42 public:
43  NoResult(Error err) : RuntimeError(err.description()), _error(std::move(err)) {}
44 
45 private:
46  Error _error;
47 };
48 
50 class NoError : public RuntimeError {
51 public:
52  NoError() : RuntimeError("<no error>") {}
53 };
54 
55 } // namespace result
56 
57 struct Nothing {};
58 
59 inline bool operator==(const Nothing&, const Nothing&) { return true; }
60 inline bool operator!=(const Nothing&, const Nothing&) { return false; }
61 
66 template<typename T>
67 class Result {
68 public:
69  Result() : _value(std::in_place_type_t<result::Error>(), result::Error("<result not initialized>")) {}
70 
72  Result(const T& t) : _value(std::in_place_type_t<T>(), t) {}
74  Result(T&& t) : _value(std::in_place_type_t<T>(), std::move(t)) {}
76  Result(const result::Error& e) : _value(std::in_place_type_t<result::Error>(), e) {}
78  Result(result::Error&& e) : _value(std::in_place_type_t<result::Error>(), std::move(e)) {}
79 
80  Result(const Result& o) = default;
81  Result(Result&& o) = default; // NOLINT (hicpp-noexcept-move)
82  ~Result() = default;
83 
90  const T& value() const { return std::get<T>(_value); }
91 
98  T& value() { return std::get<T>(_value); }
99 
107  template<typename E = result::NoResult>
108  const T& valueOrThrow() const {
109  if ( ! hasValue() )
110  throw E(error());
111 
112  return value();
113  }
114 
122  template<typename E = result::NoResult>
124  if ( ! hasValue() )
125  throw E(error());
126 
127  return value();
128  }
129 
136  const result::Error& error() const { return std::get<result::Error>(_value); }
137 
144  const result::Error& errorOrThrow() const {
145  if ( hasValue() )
146  throw result::NoError();
147 
148  return error();
149  }
150 
152  bool hasValue() const { return std::holds_alternative<T>(_value); }
153 
155  const T& operator*() const { return value(); }
157  T& operator*() { return value(); }
159  const T* operator->() const { return std::get_if<T>(&_value); }
161  T* operator->() { return std::get_if<T>(&_value); }
162 
164  explicit operator bool() const { return hasValue(); }
165 
167  operator std::optional<T>() const { return hasValue() ? std::make_optional(value()) : std::nullopt; }
168 
169  Result& operator=(const Result& other) = default;
170  Result& operator=(Result&& other) = default; // NOLINT (hicpp-noexcept-move)
171 
172  friend bool operator==(const Result& a, const Result& b) {
173  if ( a.hasValue() != b.hasValue() )
174  return false;
175 
176  if ( a.hasValue() )
177  return a.value() == b.value();
178  else
179  return a.error() == b.error();
180  }
181 
182  friend bool operator!=(const Result& a, const Result& b) { return ! (a == b); }
183 
184 private:
185  std::variant<T, result::Error> _value;
186 };
187 
188 } // namespace hilti::rt
const T & operator*() const
Definition: result.h:155
Definition: result.h:18
Definition: result.h:41
Definition: any.h:7
const T * operator->() const
Definition: result.h:159
const result::Error & error() const
Definition: result.h:136
Definition: optional.h:79
const T & valueOrThrow() const
Definition: result.h:108
Definition: result.h:50
T * operator->()
Definition: result.h:161
Result(result::Error &&e)
Definition: result.h:78
bool hasValue() const
Definition: result.h:152
T & valueOrThrow()
Definition: result.h:123
const result::Error & errorOrThrow() const
Definition: result.h:144
T & value()
Definition: result.h:98
Result(const T &t)
Definition: result.h:72
T & operator*()
Definition: result.h:157
const T & value() const
Definition: result.h:90
Result(T &&t)
Definition: result.h:74
Result(const result::Error &e)
Definition: result.h:76
Definition: result.h:57
Definition: result.h:67