|
| 1 | +#ifndef ERROR_H |
| 2 | +#define ERROR_H |
| 3 | + |
| 4 | +#include "types.h" |
| 5 | + |
| 6 | +#include <memory> |
| 7 | +#include <ostream> |
| 8 | + |
| 9 | +namespace toggl { |
| 10 | + |
| 11 | + class ErrorBase { |
| 12 | + public: |
| 13 | + virtual std::string Class() const = 0; |
| 14 | + virtual int Type() const { return 0; } |
| 15 | + virtual bool IsError() const { return true; }; |
| 16 | + virtual std::string LogMessage() const = 0; |
| 17 | + virtual std::string UserMessage() const { return ""; } |
| 18 | + |
| 19 | + bool operator==(const ErrorBase &o) const { |
| 20 | + return IsError() == o.IsError() && |
| 21 | + UserMessage() == o.UserMessage(); |
| 22 | + } |
| 23 | + }; |
| 24 | + |
| 25 | + class NoError : public ErrorBase { |
| 26 | + public: |
| 27 | + virtual std::string Class() const override { return "NoError"; } |
| 28 | + virtual bool IsError() const override { return false; } |
| 29 | + virtual std::string LogMessage() const override { return {}; } |
| 30 | + virtual std::string UserMessage() const override { return {}; } |
| 31 | + }; |
| 32 | + |
| 33 | + class Error { |
| 34 | + public: |
| 35 | + template<class T> Error(T &&e) : data_(std::make_shared<T>(std::move(e))) { } |
| 36 | + template<class T> Error(const T &e) : data_(std::make_shared<T>(e)) { } |
| 37 | + Error(Error &&o) : data_(std::move(o.data_)) { } |
| 38 | + Error(const Error &o) : data_(o.data_) { } |
| 39 | + Error &operator=(const Error &o) { |
| 40 | + data_ = o.data_; |
| 41 | + return *this; |
| 42 | + } |
| 43 | + ErrorBase *operator->() { return data_.get(); } |
| 44 | + const ErrorBase *operator->() const { return data_.get(); } |
| 45 | + ErrorBase &operator*() { return *data_.get(); } |
| 46 | + const ErrorBase &operator*() const { return *data_.get(); } |
| 47 | + bool operator==(const Error &o) const { |
| 48 | + return *data_ == *o.data_; |
| 49 | + } |
| 50 | + operator std::string() const { |
| 51 | + return data_->LogMessage(); |
| 52 | + } |
| 53 | + /** |
| 54 | + * This method is to be used to access the actual derived type, |
| 55 | + * not just the stuff that's exposed by the ErrorBase interface |
| 56 | + * |
| 57 | + * @return a shared pointer to a derived error type |
| 58 | + */ |
| 59 | + template<class T> std::shared_ptr<T> promote() { |
| 60 | + return std::dynamic_pointer_cast<T>(data_); |
| 61 | + } |
| 62 | + private: |
| 63 | + std::shared_ptr<ErrorBase> data_; |
| 64 | + }; |
| 65 | + |
| 66 | + inline std::ostream &operator<<(std::ostream &out, const Error &err) { |
| 67 | + out << err->UserMessage(); |
| 68 | + out << std::string(" "); |
| 69 | + out << err->LogMessage(); |
| 70 | + return out; |
| 71 | + } |
| 72 | + |
| 73 | + /* TODO WARNING |
| 74 | + * These operators exist only to provide backward compatibility with the string-based error class |
| 75 | + * They should be removed once all of string-based error is gone |
| 76 | + */ |
| 77 | + inline bool operator==(const Error &l, const std::string &r) { |
| 78 | + return l->LogMessage() == r; |
| 79 | + } |
| 80 | + inline bool operator!=(const Error &l, const std::string &r) { |
| 81 | + return l->LogMessage() != r; |
| 82 | + } |
| 83 | + inline bool operator==(const std::string &l, const Error &r) { |
| 84 | + return l == r->LogMessage(); |
| 85 | + } |
| 86 | + inline bool operator!=(const std::string &l, const Error &r) { |
| 87 | + return l != r->LogMessage(); |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +#endif // ERROR_H |
0 commit comments