| Index: webrtc/api/rtcerror.h
|
| diff --git a/webrtc/api/rtcerror.h b/webrtc/api/rtcerror.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..22714451b5f3239a58dfadc98e00b4d4f59f3b47
|
| --- /dev/null
|
| +++ b/webrtc/api/rtcerror.h
|
| @@ -0,0 +1,291 @@
|
| +/*
|
| + * Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license
|
| + * that can be found in the LICENSE file in the root of the source
|
| + * tree. An additional intellectual property rights grant can be found
|
| + * in the file PATENTS. All contributing project authors may
|
| + * be found in the AUTHORS file in the root of the source tree.
|
| + */
|
| +
|
| +#ifndef WEBRTC_API_RTCERROR_H_
|
| +#define WEBRTC_API_RTCERROR_H_
|
| +
|
| +#include <ostream>
|
| +#include <string>
|
| +#include <utility> // For std::move.
|
| +
|
| +#include "webrtc/base/checks.h"
|
| +#include "webrtc/base/logging.h"
|
| +
|
| +namespace webrtc {
|
| +
|
| +// Enumeration to represent distinct classes of errors that an application
|
| +// may wish to act upon differently. These roughly map to DOMExceptions or
|
| +// RTCError "errorDetailEnum" values in the web API, as described in the
|
| +// comments below.
|
| +enum class RTCErrorType {
|
| + // No error.
|
| + NONE,
|
| +
|
| + // An operation is valid, but currently unsupported.
|
| + // Maps to OperationError DOMException.
|
| + UNSUPPORTED_OPERATION,
|
| +
|
| + // A supplied parameter is valid, but currently unsupported.
|
| + // Maps to OperationError DOMException.
|
| + UNSUPPORTED_PARAMETER,
|
| +
|
| + // General error indicating that a supplied parameter is invalid.
|
| + // Maps to InvalidAccessError or TypeError DOMException depending on context.
|
| + INVALID_PARAMETER,
|
| +
|
| + // Slightly more specific than INVALID_PARAMETER; a parameter's value was
|
| + // outside the allowed range.
|
| + // Maps to RangeError DOMException.
|
| + INVALID_RANGE,
|
| +
|
| + // Slightly more specific than INVALID_PARAMETER; an error occurred while
|
| + // parsing string input.
|
| + // Maps to SyntaxError DOMException.
|
| + SYNTAX_ERROR,
|
| +
|
| + // The object does not support this operation in its current state.
|
| + // Maps to InvalidStateError DOMException.
|
| + INVALID_STATE,
|
| +
|
| + // An attempt was made to modify the object in an invalid way.
|
| + // Maps to InvalidModificationError DOMException.
|
| + INVALID_MODIFICATION,
|
| +
|
| + // An error occurred within an underlying network protocol.
|
| + // Maps to NetworkError DOMException.
|
| + NETWORK_ERROR,
|
| +
|
| + // Some resource has been exhausted; file handles, hardware resources, ports,
|
| + // etc.
|
| + // Maps to OperationError DOMException.
|
| + RESOURCE_EXHAUSTED,
|
| +
|
| + // The operation failed due to an internal error.
|
| + // Maps to OperationError DOMException.
|
| + INTERNAL_ERROR,
|
| +};
|
| +
|
| +// Roughly corresponds to RTCError in the web api. Holds an error type, a
|
| +// message, and possibly additional information specific to that error.
|
| +//
|
| +// Doesn't contain anything beyond a type and message now, but will in the
|
| +// future as more errors are implemented.
|
| +class RTCError {
|
| + public:
|
| + // Constructors.
|
| +
|
| + // Creates a "no error" error.
|
| + RTCError() {}
|
| + explicit RTCError(RTCErrorType type) : type_(type) {}
|
| + // For performance, prefer using the constructor that takes a const char* if
|
| + // the message is a static string.
|
| + RTCError(RTCErrorType type, const char* message)
|
| + : type_(type), static_message_(message), have_string_message_(false) {}
|
| + RTCError(RTCErrorType type, std::string&& message)
|
| + : type_(type), string_message_(message), have_string_message_(true) {}
|
| +
|
| + // Delete the copy constructor and assignment operator; there aren't any use
|
| + // cases where you should need to copy an RTCError, as opposed to moving it.
|
| + // Can revisit this decision if use cases arise in the future.
|
| + RTCError(const RTCError& other) = delete;
|
| + RTCError& operator=(const RTCError& other) = delete;
|
| +
|
| + // Move constructor and move-assignment operator.
|
| + RTCError(RTCError&& other);
|
| + RTCError& operator=(RTCError&& other);
|
| +
|
| + ~RTCError();
|
| +
|
| + // Identical to default constructed error.
|
| + //
|
| + // Preferred over the default constructor for code readability.
|
| + static RTCError OK();
|
| +
|
| + // Error type.
|
| + RTCErrorType type() const { return type_; }
|
| + void set_type(RTCErrorType type) { type_ = type; }
|
| +
|
| + // Human-readable message describing the error. Shouldn't be used for
|
| + // anything but logging/diagnostics, since messages are not guaranteed to be
|
| + // stable.
|
| + const char* message() const;
|
| + // For performance, prefer using the method that takes a const char* if the
|
| + // message is a static string.
|
| + void set_message(const char* message);
|
| + void set_message(std::string&& message);
|
| +
|
| + // Convenience method for situations where you only care whether or not an
|
| + // error occurred.
|
| + bool ok() const { return type_ == RTCErrorType::NONE; }
|
| +
|
| + private:
|
| + RTCErrorType type_ = RTCErrorType::NONE;
|
| + // For performance, we use static strings wherever possible. But in some
|
| + // cases the error string may need to be constructed, in which case an
|
| + // std::string is used.
|
| + union {
|
| + const char* static_message_ = "";
|
| + std::string string_message_;
|
| + };
|
| + // Whether or not |static_message_| or |string_message_| is being used in the
|
| + // above union.
|
| + bool have_string_message_ = false;
|
| +};
|
| +
|
| +// Outputs the error as a friendly string. Update this method when adding a new
|
| +// error type.
|
| +//
|
| +// Only intended to be used for logging/disagnostics.
|
| +std::ostream& operator<<(std::ostream& stream, RTCErrorType error);
|
| +
|
| +// Helper macro that can be used by implementations to create an error with a
|
| +// message and log it. |message| should be a string literal or movable
|
| +// std::string.
|
| +#define LOG_AND_RETURN_ERROR_EX(type, message, severity) \
|
| + { \
|
| + RTC_DCHECK(type != RTCErrorType::NONE); \
|
| + LOG(severity) << message << " (" << type << ")"; \
|
| + return webrtc::RTCError(type, message); \
|
| + }
|
| +
|
| +#define LOG_AND_RETURN_ERROR(type, message) \
|
| + LOG_AND_RETURN_ERROR_EX(type, message, LS_ERROR)
|
| +
|
| +// RTCErrorOr<T> is the union of an RTCError object and a T object. RTCErrorOr
|
| +// models the concept of an object that is either a usable value, or an error
|
| +// Status explaining why such a value is not present. To this end RTCErrorOr<T>
|
| +// does not allow its RTCErrorType value to be RTCErrorType::NONE. This is
|
| +// enforced by a debug check in most cases.
|
| +//
|
| +// The primary use-case for RTCErrorOr<T> is as the return value of a function
|
| +// which may fail. For example, CreateRtpSender will fail if the parameters
|
| +// could not be successfully applied at the media engine level, but if
|
| +// successful will return a unique_ptr to an RtpSender.
|
| +//
|
| +// Example client usage for a RTCErrorOr<std::unique_ptr<T>>:
|
| +//
|
| +// RTCErrorOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
|
| +// if (result.ok()) {
|
| +// std::unique_ptr<Foo> foo = result.ConsumeValue();
|
| +// foo->DoSomethingCool();
|
| +// } else {
|
| +// LOG(LS_ERROR) << result.error();
|
| +// }
|
| +//
|
| +// Example factory implementation returning RTCErrorOr<std::unique_ptr<T>>:
|
| +//
|
| +// RTCErrorOr<std::unique_ptr<Foo>> FooFactory::MakeNewFoo(int arg) {
|
| +// if (arg <= 0) {
|
| +// return RTCError(RTCErrorType::INVALID_RANGE, "Arg must be positive");
|
| +// } else {
|
| +// return std::unique_ptr<Foo>(new Foo(arg));
|
| +// }
|
| +// }
|
| +//
|
| +template <typename T>
|
| +class RTCErrorOr {
|
| + // Used to convert between RTCErrorOr<Foo>/RtcErrorOr<Bar>, when an implicit
|
| + // conversion from Foo to Bar exists.
|
| + template <typename U>
|
| + friend class RTCErrorOr;
|
| +
|
| + public:
|
| + typedef T element_type;
|
| +
|
| + // Constructs a new RTCErrorOr with RTCErrorType::INTERNAL_ERROR error. This
|
| + // is marked 'explicit' to try to catch cases like 'return {};', where people
|
| + // think RTCErrorOr<std::vector<int>> will be initialized with an empty
|
| + // vector, instead of a RTCErrorType::INTERNAL_ERROR error.
|
| + explicit RTCErrorOr() : error_(RTCErrorType::INTERNAL_ERROR) {}
|
| +
|
| + // Constructs a new RTCErrorOr with the given non-ok error. After calling
|
| + // this constructor, calls to value() will DCHECK-fail.
|
| + //
|
| + // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return
|
| + // value, so it is convenient and sensible to be able to do 'return
|
| + // RTCError(...)' when the return type is RTCErrorOr<T>.
|
| + //
|
| + // REQUIRES: !error.ok(). This requirement is DCHECKed.
|
| + RTCErrorOr(RTCError&& error) : error_(std::move(error)) {
|
| + RTC_DCHECK(!error.ok());
|
| + }
|
| +
|
| + // Constructs a new RTCErrorOr with the given value. After calling this
|
| + // constructor, calls to value() will succeed, and calls to error() will
|
| + // return a default-constructed RTCError.
|
| + //
|
| + // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return type
|
| + // so it is convenient and sensible to be able to do 'return T()'
|
| + // when the return type is RTCErrorOr<T>.
|
| + RTCErrorOr(T value) : value_(std::move(value)) {}
|
| +
|
| + // Delete the copy constructor and assignment operator; there aren't any use
|
| + // cases where you should need to copy an RTCErrorOr, as opposed to moving
|
| + // it. Can revisit this decision if use cases arise in the future.
|
| + RTCErrorOr(const RTCErrorOr& other) = delete;
|
| + RTCErrorOr& operator=(const RTCErrorOr& other) = delete;
|
| +
|
| + // Move constructor and move-assignment operator.
|
| + RTCErrorOr(RTCErrorOr&& other) = default;
|
| + RTCErrorOr& operator=(RTCErrorOr&& other) = default;
|
| +
|
| + // Conversion constructor and assignment operator; T must be copy or move
|
| + // constructible from U.
|
| + template <typename U>
|
| + RTCErrorOr(RTCErrorOr<U> other)
|
| + : error_(std::move(other.error_)), value_(std::move(other.value_)) {}
|
| + template <typename U>
|
| + RTCErrorOr& operator=(RTCErrorOr<U> other) {
|
| + error_ = std::move(other.error_);
|
| + value_ = std::move(other.value_);
|
| + return *this;
|
| + }
|
| +
|
| + // Returns a reference to our error. If this contains a T, then returns
|
| + // default-constructed RTCError.
|
| + const RTCError& error() const { return error_; }
|
| +
|
| + // Moves the error. Can be useful if, say "CreateFoo" returns an
|
| + // RTCErrorOr<Foo>, and internally calls "CreateBar" which returns an
|
| + // RTCErrorOr<Bar>, and wants to forward the error up the stack.
|
| + RTCError MoveError() { return std::move(error_); }
|
| +
|
| + // Returns this->error().ok()
|
| + bool ok() const { return error_.ok(); }
|
| +
|
| + // Returns a reference to our current value, or DCHECK-fails if !this->ok().
|
| + //
|
| + // Can be convenient for the implementation; for example, a method may want
|
| + // to access the value in some way before returning it to the next method on
|
| + // the stack.
|
| + const T& value() const {
|
| + RTC_DCHECK(ok());
|
| + return value_;
|
| + }
|
| + T& value() {
|
| + RTC_DCHECK(ok());
|
| + return value_;
|
| + }
|
| +
|
| + // Moves our current value out of this object and returns it, or DCHECK-fails
|
| + // if !this->ok().
|
| + T MoveValue() {
|
| + RTC_DCHECK(ok());
|
| + return std::move(value_);
|
| + }
|
| +
|
| + private:
|
| + RTCError error_;
|
| + T value_;
|
| +};
|
| +
|
| +} // namespace webrtc
|
| +
|
| +#endif // WEBRTC_API_RTCERROR_H_
|
|
|