Files
nearby/cpp/platform/base/exception.h
T
Alexey Polyudov 2155b3ddeb Roll forward to cl/338482889
Signed-off-by: Alexey Polyudov <apolyudov@google.com>
Change-Id: I9850950db8bd84f0904ea1a413151887f52098cf
2020-10-22 10:47:34 -07:00

99 lines
3.1 KiB
C++

#ifndef PLATFORM_BASE_EXCEPTION_H_
#define PLATFORM_BASE_EXCEPTION_H_
#include <utility>
#include "absl/meta/type_traits.h"
namespace location {
namespace nearby {
struct Exception {
enum Value : int {
kFailed = -1, // Initial value of Exception; any unknown error.
kSuccess = 0, // No exception.
kIo = 1, // IO Error happened.
kInterrupted = 2, // Operation was interrupted.
kInvalidProtocolBuffer = 3, // Couldn't parse.
kExecution = 4, // Couldn't execute.
kTimeout = 5, // Operarion did not finish within specified time.
};
bool Ok() const { return value == kSuccess; }
bool Raised() const { return !Ok(); }
bool Raised(Value value) const { return this->value == value; }
Value value{kFailed};
};
constexpr inline bool operator==(const Exception& a, const Exception& b) {
return a.value == b.value;
}
constexpr inline bool operator!=(const Exception& a, const Exception& b) {
return !(a == b);
}
// ExceptionOr provides experience similar to StatusOr<T> used in
// Google Cloud API, see:
// https://googleapis.github.io/google-cloud-cpp/0.7.0/common/status__or_8h_source.html
//
// If ok() returns true, result() is a usable return value. Otherwise,
// exception() explains why such a value is not present.
//
// A typical pattern of usage is as follows:
//
// if (!e.ok()) {
// if (Exception::EXCEPTION_TYPE_1 == e.exception()) {
// // Handle Exception::EXCEPTION_TYPE_1.
// } else if (Exception::EXCEPTION_TYPE_2 == e.exception()) {
// // Handle Exception::EXCEPTION_TYPE_2.
// }
//
// return;
// }
//
// // Use e.result().
template <typename T>
class ExceptionOr {
public:
ExceptionOr() = default;
explicit ExceptionOr(T&& result)
: result_{std::move(result)},
exception_{Exception::kSuccess} {} // NOLINT
explicit ExceptionOr(const T& result)
: result_{result}, exception_{Exception::kSuccess} {} // NOLINT
ExceptionOr(Exception::Value exception) : exception_{exception} {} // NOLINT
ExceptionOr(Exception exception) : exception_{exception} {} // NOLINT
// If there exists explicit conversion from from U to T,
// then allow explicit conversion from ExceptionOr<U> to ExceptionOr<T>.
template <typename U, typename = absl::void_t<decltype(T{std::declval<U>()})>>
explicit ExceptionOr<T>(ExceptionOr<U> value) {
if (!value.ok()) {
exception_ = value.GetException();
} else {
result_ = T{std::move(value.result())};
exception_ = Exception{Exception::kSuccess};
}
}
bool ok() const { return exception_.value == Exception::kSuccess; }
T& result() & { return result_; }
const T& result() const& { return result_; }
T&& result() && { return std::move(result_); }
const T&& result() const&& { return std::move(result_); }
Exception::Value exception() const { return exception_.value; }
T GetResult() const { return result_; }
Exception GetException() const { return exception_; }
private:
T result_{};
Exception exception_{Exception::kFailed};
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_BASE_EXCEPTION_H_