Chromium Code Reviews| Index: webrtc/api/rtcerror.h |
| diff --git a/webrtc/api/rtcerror.h b/webrtc/api/rtcerror.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b032f332d5f6258301bf1b26adc8ece27039609f |
| --- /dev/null |
| +++ b/webrtc/api/rtcerror.h |
| @@ -0,0 +1,257 @@ |
| +/* |
| + * 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() = default; |
| + explicit RTCError(RTCErrorType type) : type_(type) {} |
| + RTCError(RTCErrorType type, const std::string& message) |
| + : type_(type), message_(message) {} |
| + |
| + // Identical to default constructed error. |
| + // |
| + // Preferred over the default constructor for code readability, and reducing |
| + // unnecessary copies. |
| + static const 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 std::string& message() const { return message_; } |
| + void set_message(const std::string& message) { message_ = message; } |
|
tommi
2017/02/13 18:17:14
is this method necessary? It could have benefits t
Taylor Brandstetter
2017/02/13 18:44:18
The PeerConnection methods that take an "RTCError*
|
| + |
| + // 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; |
| + std::string message_; |
|
tommi
2017/02/13 12:10:01
Can we avoid allocating a string for every error?
Taylor Brandstetter
2017/02/13 18:03:53
No, there are cases where I want to build the stri
tommi
2017/02/13 18:17:14
I think the answer to "Won't some be either empty
Taylor Brandstetter
2017/02/13 18:44:17
Oh, I didn't see "some", sorry.
Hmm. But if "mess
|
| +}; |
| + |
| +// 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 method that can be used by implementations to create an error with a |
| +// message and log it. |
| +webrtc::RTCError CreateAndLogError(webrtc::RTCErrorType type, |
| + const std::string& message, |
| + rtc::LoggingSeverity severity); |
| + |
| +// Logs at error level. |
| +webrtc::RTCError CreateAndLogError(webrtc::RTCErrorType type, |
| + const std::string& message); |
| + |
| +// 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::NONE 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::NONE error. |
| + explicit RTCErrorOr() = default; |
| + |
| + // 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(const RTCError& error) : error_(error) { RTC_DCHECK(!error.ok()); } |
| + 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_; } |
| + |
| + // 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_; |
|
tommi
2017/02/13 12:10:01
this also means that every return value that uses
Taylor Brandstetter
2017/02/13 18:03:53
I'd hoped that, by using move constructors/assignm
tommi
2017/02/13 18:17:14
I understand. The overhead can still be reduced fu
|
| + T value_; |
| +}; |
| + |
| +} // namespace webrtc |
| + |
| +#endif // WEBRTC_API_RTCERROR_H_ |