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 
106  const T& valueOrThrow() const {
107  if ( ! hasValue() )
108  throw result::NoResult(error());
109 
110  return value();
111  }
112 
120  if ( ! hasValue() )
121  throw result::NoResult(error());
122 
123  return value();
124  }
125 
132  const result::Error& error() const { return std::get<result::Error>(_value); }
133 
140  const result::Error& errorOrThrow() const {
141  if ( hasValue() )
142  throw result::NoError();
143 
144  return error();
145  }
146 
148  bool hasValue() const { return std::holds_alternative<T>(_value); }
149 
151  const T& operator*() const { return value(); }
153  T& operator*() { return value(); }
155  const T* operator->() const { return std::get_if<T>(&_value); }
157  T* operator->() { return std::get_if<T>(&_value); }
158 
160  explicit operator bool() const { return hasValue(); }
161 
163  operator std::optional<T>() const { return hasValue() ? std::make_optional(value()) : std::nullopt; }
164 
165  Result& operator=(const Result& other) = default;
166  Result& operator=(Result&& other) = default; // NOLINT (hicpp-noexcept-move)
167 
168  friend bool operator==(const Result& a, const Result& b) {
169  if ( a.hasValue() != b.hasValue() )
170  return false;
171 
172  if ( a.hasValue() )
173  return a.value() == b.value();
174  else
175  return a.error() == b.error();
176  }
177 
178  friend bool operator!=(const Result& a, const Result& b) { return ! (a == b); }
179 
180 private:
181  std::variant<T, result::Error> _value;
182 };
183 
184 } // namespace hilti::rt
const T & operator*() const
Definition: result.h:151
Definition: result.h:18
Definition: result.h:41
Definition: any.h:7
const T * operator->() const
Definition: result.h:155
const result::Error & error() const
Definition: result.h:132
Definition: optional.h:79
const T & valueOrThrow() const
Definition: result.h:106
T & valueOrThrow()
Definition: result.h:119
Definition: result.h:50
T * operator->()
Definition: result.h:157
Result(result::Error &&e)
Definition: result.h:78
bool hasValue() const
Definition: result.h:148
const result::Error & errorOrThrow() const
Definition: result.h:140
T & value()
Definition: result.h:98
Result(const T &t)
Definition: result.h:72
T & operator*()
Definition: result.h:153
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