Spicy
result.h
1 // Copyright (c) 2020-now 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 
62 namespace detail::adl {
63 inline std::string to_string(const Nothing& n, adl::tag /*unused*/) { return "<nothing>"; };
64 } // namespace detail::adl
65 
70 template<typename T>
71 class Result {
72 public:
73  Result() : _value(std::in_place_type_t<result::Error>(), result::Error("<result not initialized>")) {}
74 
76  Result(const T& t) : _value(std::in_place_type_t<T>(), t) {}
78  Result(T&& t) : _value(std::in_place_type_t<T>(), std::move(t)) {}
80  Result(const result::Error& e) : _value(std::in_place_type_t<result::Error>(), e) {}
82  Result(result::Error&& e) : _value(std::in_place_type_t<result::Error>(), std::move(e)) {}
83 
84  Result(const Result& o) = default;
85  Result(Result&& o) = default; // NOLINT (hicpp-noexcept-move)
86  ~Result() = default;
87 
94  const T& value() const { return std::get<T>(_value); }
95 
102  T& value() { return std::get<T>(_value); }
103 
111  template<typename E = result::NoResult>
112  const T& valueOrThrow() const {
113  if ( ! hasValue() )
114  throw E(error());
115 
116  return value();
117  }
118 
126  template<typename E = result::NoResult>
128  if ( ! hasValue() )
129  throw E(error());
130 
131  return value();
132  }
133 
140  const result::Error& error() const { return std::get<result::Error>(_value); }
141 
148  const result::Error& errorOrThrow() const {
149  if ( hasValue() )
150  throw result::NoError();
151 
152  return error();
153  }
154 
156  bool hasValue() const { return std::holds_alternative<T>(_value); }
157 
159  const T& operator*() const { return value(); }
161  T& operator*() { return value(); }
163  const T* operator->() const { return std::get_if<T>(&_value); }
165  T* operator->() { return std::get_if<T>(&_value); }
166 
168  explicit operator bool() const { return hasValue(); }
169 
171  operator std::optional<T>() const { return hasValue() ? std::make_optional(value()) : std::nullopt; }
172 
173  Result& operator=(const Result& other) = default;
174  Result& operator=(Result&& other) = default; // NOLINT (hicpp-noexcept-move)
175 
176  friend bool operator==(const Result& a, const Result& b) {
177  if ( a.hasValue() != b.hasValue() )
178  return false;
179 
180  if ( a.hasValue() )
181  return a.value() == b.value();
182  else
183  return a.error() == b.error();
184  }
185 
186  friend bool operator!=(const Result& a, const Result& b) { return ! (a == b); }
187 
188 private:
189  std::variant<T, result::Error> _value;
190 };
191 
193 template<typename T>
195  return Result<T>(std::forward<T>(t));
196 }
197 
198 } // namespace hilti::rt
Definition: result.h:71
T & value()
Definition: result.h:102
Result(const result::Error &e)
Definition: result.h:80
T * operator->()
Definition: result.h:165
const T & valueOrThrow() const
Definition: result.h:112
const result::Error & error() const
Definition: result.h:140
const result::Error & errorOrThrow() const
Definition: result.h:148
const T & value() const
Definition: result.h:94
bool hasValue() const
Definition: result.h:156
const T * operator->() const
Definition: result.h:163
T & valueOrThrow()
Definition: result.h:127
Result(const T &t)
Definition: result.h:76
Result(T &&t)
Definition: result.h:78
T & operator*()
Definition: result.h:161
const T & operator*() const
Definition: result.h:159
Result(result::Error &&e)
Definition: result.h:82
Definition: result.h:18
Definition: result.h:50
Definition: result.h:41
Definition: any.h:7
std::string to_string(T &&x)
Definition: extension-points.h:26
Result< T > make_result(T &&t)
Definition: result.h:194
Definition: result.h:57