1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
|
/*
* 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 API_RTCERROR_H_
#define API_RTCERROR_H_
#ifdef UNIT_TEST
#include <ostream>
#endif // UNIT_TEST
#include <string>
#include <utility> // For std::move.
#include "rtc_base/checks.h"
#include "rtc_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::string ToString(RTCErrorType error);
#ifdef UNIT_TEST
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
RTCErrorType error) {
return stream << ToString(error);
}
#endif // UNIT_TEST
// 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); \
RTC_LOG(severity) << message << " (" << ToString(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 {
// RTC_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.
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)) { // NOLINT
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)) {} // NOLINT
// 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.
//
// Visual Studio doesn't support "= default" with move constructors or
// assignment operators (even though they compile, they segfault), so define
// them explicitly.
RTCErrorOr(RTCErrorOr&& other)
: error_(std::move(other.error_)), value_(std::move(other.value_)) {}
RTCErrorOr& operator=(RTCErrorOr&& other) {
error_ = std::move(other.error_);
value_ = std::move(other.value_);
return *this;
}
// Conversion constructor and assignment operator; T must be copy or move
// constructible from U.
template <typename U>
RTCErrorOr(RTCErrorOr<U> other) // NOLINT
: 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 // API_RTCERROR_H_
|