ROSE  0.11.98.0
Result.h
1 // WARNING: Changes to this file must be contributed back to Sawyer or else they will
2 // be clobbered by the next update from Sawyer. The Sawyer repository is at
3 // https://github.com/matzke1/sawyer.
4 
5 
6 
7 
8 #ifndef Sawyer_Result_H
9 #define Sawyer_Result_H
10 
11 #include <Sawyer/Optional.h>
12 
13 #include <boost/lexical_cast.hpp>
14 #include <boost/serialization/access.hpp>
15 #include <boost/serialization/nvp.hpp>
16 #include <boost/serialization/split_member.hpp>
17 #include <boost/variant.hpp>
18 #include <exception>
19 #include <string>
20 #include <type_traits>
21 
22 namespace Sawyer {
23 
24 template <class F, class... Args>
26 {
27  template <class U>
28  static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
29  template <class U>
30  static auto test(...) -> decltype(std::false_type());
31 
32  static constexpr bool value = decltype(test<F>(0))::value;
33 };
34 
35 
37 template<class T>
38 class Ok {
39 public:
40  using Value = T;
41 
42 private:
43  Value ok_;
44 
45 private:
46  friend class boost::serialization::access;
47 
48  template<class S>
49  void serialize(S &s, const unsigned /*version*/) {
50  s & BOOST_SERIALIZATION_NVP(ok_);
51  }
52 
53 public:
54  Ok() = delete;
55 
57  explicit Ok(const Ok &other)
58  : ok_(other.ok_) {}
59 
61  explicit Ok(const Value &ok)
62  : ok_(ok) {}
63 
67  Ok& operator=(const Ok &other) {
68  ok_ = other.ok_;
69  return *this;
70  }
71  Ok& operator=(const Value &ok) {
72  ok_ = ok;
73  return *this;
74  }
78  const Value& operator*() const {
79  return ok_;
80  }
81 
83  const Value* operator->() const {
84  return &ok_;
85  }
86 };
87 
88 // Specialization for Ok that stores string literals, as in Ok("foo"). These get treated as std::string instead.
89 template<size_t N>
90 class Ok<char[N]> {
91 public:
92  using Value = std::string;
93 
94 private:
95  std::string ok_;
96 
97 private:
98  friend class boost::serialization::access;
99 
100  template<class S>
101  void serialize(S &s, const unsigned /*version*/) {
102  s & BOOST_SERIALIZATION_NVP(ok_);
103  }
104 
105 public:
106  Ok() = delete;
107 
108  explicit Ok(const Value &s)
109  : ok_(s) {}
110 
111  Ok& operator=(const Ok &other) {
112  ok_ = other.ok_;
113  return *this;
114  }
115 
116  Ok& operator=(const Value &ok) {
117  ok_ = ok;
118  return *this;
119  }
120 
121  const Value& operator*() const {
122  return ok_;
123  }
124 
125  const Value* operator->() const {
126  return &ok_;
127  }
128 };
129 
131 template<class E>
132 class Error {
133 public:
134  using Value = E;
135 
136 private:
137  Value error_;
138 
139 private:
140  friend class boost::serialization::access;
141 
142  template<class S>
143  void serialize(S &s, const unsigned /*version*/) {
144  s & BOOST_SERIALIZATION_NVP(error_);
145  }
146 
147 public:
148  Error() = delete;
149 
151  explicit Error(const Error &other)
152  : error_(other.error_) {}
153 
155  explicit Error(const E &error)
156  : error_(error) {}
157 
161  Error& operator=(const Error &other) {
162  error_ = other.error_;
163  return *this;
164  }
165  Error& operator=(const Value &error) {
166  error_ = error;
167  return *this;
168  }
172  const Value& operator*() const {
173  return error_;
174  }
175 
177  const Value* operator->() const {
178  return &error_;
179  }
180 };
181 
182 // Specialization for Error that stores string literals as in Error("syntax error"). It stores them as std::string instead.
183 template<size_t N>
184 class Error<char[N]> {
185 public:
186  using Value = std::string;
187 
188 private:
189  std::string error_;
190 
191 private:
192  friend class boost::serialization::access;
193 
194  template<class S>
195  void serialize(S &s, const unsigned /*version*/) {
196  s & BOOST_SERIALIZATION_NVP(error_);
197  }
198 
199 public:
200  Error() = delete;
201 
203  explicit Error(const Error &other)
204  : error_(other.error_) {}
205 
207  explicit Error(const Value &error)
208  : error_(error) {}
209 
213  Error& operator=(const Error &other) {
214  error_ = other.error_;
215  return *this;
216  }
217  Error& operator=(const Value &error) {
218  error_ = error;
219  return *this;
220  }
224  const Value& operator*() const {
225  return error_;
226  }
227 
229  const Value* operator->() const {
230  return &error_;
231  }
232 };
233 
235 template<class T, class E>
236 class Result {
237 public:
238  using OkValue = T;
239  using ErrorValue = E;
240  using OkType = Ok<T>;
241  using ErrorType = Error<E>;
242 
243 private:
244  boost::variant<Ok<T>, Error<E>> result_;
245 
246 private:
247  friend class boost::serialization::access;
248 
249  template<class S>
250  void save(S &s, const unsigned /*version*/) const {
251  s <<boost::serialization::make_nvp("isOk", isOk());
252  if (isOk()) {
253  s <<boost::serialization::make_nvp("ok", unwrap());
254  } else {
255  s <<boost::serialization::make_nvp("error", unwrapError());
256  }
257  }
258 
259  template<class S>
260  void load(S &s, const unsigned /*version*/) {
261  bool isOk;
262  s >>boost::serialization::make_nvp("isOk", isOk);
263  if (isOk) {
264  T ok;
265  s >>boost::serialization::make_nvp("ok", ok);
266  result_ = OkType(ok);
267  } else {
268  E error;
269  s >>boost::serialization::make_nvp("error", error);
270  result_ = ErrorType(error);
271  }
272  }
273 
274  BOOST_SERIALIZATION_SPLIT_MEMBER();
275 
276 public:
277  template<class U = T>
278  /*implicit*/ Result(const Ok<U> &ok)
279  : result_(OkType(*ok)) {}
280 
281  template<class F = E>
282  /*implicit*/ Result(const Error<F> &error)
283  : result_(ErrorType(*error)) {}
284 
286  template<class U = T>
287  Result& operator=(const Ok<U> &ok) {
288  result_ = OkType(*ok);
289  return *this;
290  }
291 
293  template<class F = E>
294  Result& operator=(const Error<F> &error) {
295  result_ = ErrorType(*error);
296  return *this;
297  }
298 
300  template<class U = T>
301  bool operator==(const Ok<U> &ok) const {
302  return isOk() && *this->ok() == *ok;
303  }
304 
306  template<class U = T>
307  bool operator!=(const Ok<U> &ok) const {
308  return !(*this == ok);
309  }
310 
312  template<class F = E>
313  bool operator==(const Error<F> &error) const {
314  return isError() && *this->error() == *error;
315  }
316 
318  template<class F = E>
319  bool operator!=(const Error<F> &error) const {
320  return !(*this == error);
321  }
322 
324  template<class U, class F>
325  bool operator==(const Result<U, F> &other) const {
326  return ((isOk() && other.isOk() && *ok() == *other.ok()) ||
327  (isError() && other.isError() && *error() == *other.error()));
328  }
329 
331  template<class U, class F>
332  bool operator!=(const Result<U, F> &other) const {
333  return !(*this == other);
334  }
335 
339  bool isOk() const {
340  return result_.which() == 0;
341  }
342  operator bool() const {
343  return isOk();
344  }
348  bool isError() const {
349  return !isOk();
350  }
351 
355  const Sawyer::Optional<T> ok() const {
356  if (isOk()) {
357  return *boost::get<OkType>(result_);
358  } else {
359  return Sawyer::Nothing();
360  }
361  }
362 
366  const Sawyer::Optional<E> error() const {
367  if (isOk()) {
368  return Sawyer::Nothing();
369  } else {
370  return *boost::get<ErrorType>(result_);
371  }
372  }
373 
377  const T& expect(const std::string &mesg) const {
378  if (isOk()) {
379  return *boost::get<OkType>(result_);
380  } else {
381  throw std::runtime_error(mesg);
382  }
383  }
384 
390  const T& unwrap() const {
391  return expect("result is not okay");
392  }
393  const T& operator*() const {
394  return unwrap();
395  }
399  const T orElse(const T &dflt) const {
400  return isOk() ? unwrap() : dflt;
401  }
402 
407  template<class Fn>
408  typename std::enable_if<is_invocable<Fn, ErrorValue>::value, const Result>::type
409  orElse(Fn fn) const {
410  if (isOk()) {
411  return *this;
412  } else {
413  return fn(*error());
414  }
415  }
416 
420  template<class F>
421  const Result<T, F> orElse(const Result<T, F> &other) const {
422  if (isOk()) {
423  return boost::get<OkType>(result_);
424  } else {
425  return other;
426  }
427  }
428 
430  const T& orDefault() const {
431  static T dflt = T();
432  return isOk() ? unwrap() : dflt;
433  }
434 
439  template<class Exception = E>
440  const T& orThrow() const {
441  if (isOk()) {
442  return unwrap();
443  } else {
444  throw Exception(*error());
445  }
446  }
447 
449  template<class Exception = E>
450  const T& orThrow(const Exception &e) const {
451  if (isOk()) {
452  return unwrap();
453  } else {
454  throw e;
455  }
456  }
457 
462  template<class Fn>
463  typename std::enable_if<is_invocable<Fn, OkValue>::value, const Result>::type
464  andThen(Fn fn) const {
465  if (isOk()) {
466  return fn(*ok());
467  } else {
468  return *this;
469  }
470  }
471 
475  template<class U>
476  const Result<U, E> andThen(const Result<U, E> &other) const {
477  if (isOk()) {
478  return other;
479  } else {
480  return boost::get<ErrorType>(result_);
481  }
482  }
483 
487  const E& expectError(const std::string &mesg) const {
488  if (isOk()) {
489  throw std::runtime_error(mesg);
490  } else {
491  return *boost::get<ErrorType>(result_);
492  }
493  }
494 
498  const E& unwrapError() const {
499  return expectError("result is not an error");
500  }
501 
503  template<class U>
504  bool contains(const U &value) const {
505  return isOk() ? unwrap() == value : false;
506  }
507 
509  template<class F>
510  bool containsError(const F &error) const {
511  return isOk() ? false : unwrapError() == error;
512  }
513 
514 #if 0 // [Robb Matzke 2022-08-17]
515 
521  transpose() const {
522  if (isOk()) {
523  if (unwrap().isEmpty()) {
524  return Sawyer::Nothing();
525  } else {
526  return OkType(*unwrap());
527  }
528  } else {
529  return ErrorType(unwrapError());
530  }
531  }
532 
534  Result<typename OkValue::OkValue, E> flatten() const {
535  if (isOk()) {
536  if (unwrap().isOk()) {
537  return OkValue::OkType(unwrap().unwrap());
538  } else {
539  return ErrorType(unwrap().unwrapError());
540  }
541  } else {
542  return ErrorType(unwrapError());
543  }
544  }
545 #endif
546 
550  template<class U>
551  bool assignTo(U &out) const {
552  if (isOk()) {
553  out = unwrap();
554  return true;
555  } else {
556  return false;
557  }
558  }
559 };
560 
561 } // namespace
562 #endif
Error(const E &error)
Construct from a value.
Definition: Result.h:155
bool operator!=(const Result< U, F > &other) const
Test whether this result is unequal to the other result.
Definition: Result.h:332
Success value.
Definition: Result.h:38
const T & expect(const std::string &mesg) const
Returns the success value or throws an exception.
Definition: Result.h:377
Error value.
Definition: Result.h:132
const Value * operator->() const
Dereference to obtain pointer to error.
Definition: Result.h:177
const T & orDefault() const
Returns the okay value or a default constructed value.
Definition: Result.h:430
const T & orThrow() const
Returns the value or throws an exception.
Definition: Result.h:440
const Value & operator*() const
Dereference to obtain value.
Definition: Result.h:78
Result & operator=(const Ok< U > &ok)
Assign an Ok value to this result.
Definition: Result.h:287
Error(const Value &error)
Construct from a value.
Definition: Result.h:207
const Sawyer::Optional< T > ok() const
Convert to Optional.
Definition: Result.h:355
Holds a value or nothing.
Definition: Optional.h:49
Error & operator=(const Error &other)
Assignment.
Definition: Result.h:161
Result containing a value or an error.
Definition: Result.h:236
const Result< T, F > orElse(const Result< T, F > &other) const
Returns this value or the other result.
Definition: Result.h:421
bool operator!=(const Ok< U > &ok) const
Test whether this result does not have the specified Ok value.
Definition: Result.h:307
const Value * operator->() const
Dereference to obtain pointer to error.
Definition: Result.h:229
bool containsError(const F &error) const
Returns true if this result contains the specified error value.
Definition: Result.h:510
Name space for the entire library.
Definition: FeasiblePath.h:773
bool assignTo(U &out) const
Conditionally save a value.
Definition: Result.h:551
const E & unwrapError() const
Returns the error value or throws an exception.
Definition: Result.h:498
Error & operator=(const Value &error)
Assignment.
Definition: Result.h:165
bool isError() const
Returns true if the result is an error.
Definition: Result.h:348
Error(const Error &other)
Copy constructor.
Definition: Result.h:151
Error & operator=(const Error &other)
Assignment.
Definition: Result.h:213
std::enable_if< is_invocable< Fn, ErrorValue >::value, const Result >::type orElse(Fn fn) const
Returns the contained Ok value, or calls a function.
Definition: Result.h:409
const T & operator*() const
Returns the success value or throws an exception.
Definition: Result.h:393
bool isOk() const
Returns true if the result is okay.
Definition: Result.h:339
const T orElse(const T &dflt) const
Returns the contained Ok value or a provided default.
Definition: Result.h:399
Ok(const Ok &other)
Copy constructor.
Definition: Result.h:57
Ok & operator=(const Value &ok)
Assignment.
Definition: Result.h:71
bool contains(const U &value) const
Returns true if this result contains the specified okay value.
Definition: Result.h:504
bool operator!=(const Error< F > &error) const
Test whether this result does not have the specified Error value.
Definition: Result.h:319
const Value & operator*() const
Dereference to obtain error.
Definition: Result.h:224
bool operator==(const Result< U, F > &other) const
Test whether this result is equal to the other result.
Definition: Result.h:325
Ok & operator=(const Ok &other)
Assignment.
Definition: Result.h:67
std::enable_if< is_invocable< Fn, OkValue >::value, const Result >::type andThen(Fn fn) const
Returns the contained Error value, or calls a function.
Definition: Result.h:464
const Sawyer::Optional< E > error() const
Convert to Optional.
Definition: Result.h:366
Result & operator=(const Error< F > &error)
Assign an Error value to this result.
Definition: Result.h:294
const E & expectError(const std::string &mesg) const
Returns the error value or throws an exception.
Definition: Result.h:487
Error & operator=(const Value &error)
Assignment.
Definition: Result.h:217
Represents no value.
Definition: Optional.h:32
Error(const Error &other)
Copy constructor.
Definition: Result.h:203
const T & unwrap() const
Returns the success value or throws an exception.
Definition: Result.h:390
bool operator==(const Ok< U > &ok) const
Test whether this result has the specified Ok value.
Definition: Result.h:301
const T & orThrow(const Exception &e) const
Returns the value or throws an exception constructed from the specified value.
Definition: Result.h:450
const Value & operator*() const
Dereference to obtain error.
Definition: Result.h:172
const Result< U, E > andThen(const Result< U, E > &other) const
Returns this error or the other result.
Definition: Result.h:476
Ok(const Value &ok)
Construct from an value.
Definition: Result.h:61
bool operator==(const Error< F > &error) const
Test whether this result has the specified Error value.
Definition: Result.h:313
const Value * operator->() const
Dereference to obtain pointer.
Definition: Result.h:83