1 /* 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef API_RTCERROR_H_ 12 #define API_RTCERROR_H_ 13 14 #include <ostream> 15 #include <string> 16 #include <utility> // For std::move. 17 18 #include "rtc_base/checks.h" 19 #include "rtc_base/logging.h" 20 21 namespace webrtc { 22 23 // Enumeration to represent distinct classes of errors that an application 24 // may wish to act upon differently. These roughly map to DOMExceptions or 25 // RTCError "errorDetailEnum" values in the web API, as described in the 26 // comments below. 27 enum class RTCErrorType { 28 // No error. 29 NONE, 30 31 // An operation is valid, but currently unsupported. 32 // Maps to OperationError DOMException. 33 UNSUPPORTED_OPERATION, 34 35 // A supplied parameter is valid, but currently unsupported. 36 // Maps to OperationError DOMException. 37 UNSUPPORTED_PARAMETER, 38 39 // General error indicating that a supplied parameter is invalid. 40 // Maps to InvalidAccessError or TypeError DOMException depending on context. 41 INVALID_PARAMETER, 42 43 // Slightly more specific than INVALID_PARAMETER; a parameter's value was 44 // outside the allowed range. 45 // Maps to RangeError DOMException. 46 INVALID_RANGE, 47 48 // Slightly more specific than INVALID_PARAMETER; an error occurred while 49 // parsing string input. 50 // Maps to SyntaxError DOMException. 51 SYNTAX_ERROR, 52 53 // The object does not support this operation in its current state. 54 // Maps to InvalidStateError DOMException. 55 INVALID_STATE, 56 57 // An attempt was made to modify the object in an invalid way. 58 // Maps to InvalidModificationError DOMException. 59 INVALID_MODIFICATION, 60 61 // An error occurred within an underlying network protocol. 62 // Maps to NetworkError DOMException. 63 NETWORK_ERROR, 64 65 // Some resource has been exhausted; file handles, hardware resources, ports, 66 // etc. 67 // Maps to OperationError DOMException. 68 RESOURCE_EXHAUSTED, 69 70 // The operation failed due to an internal error. 71 // Maps to OperationError DOMException. 72 INTERNAL_ERROR, 73 }; 74 75 // Roughly corresponds to RTCError in the web api. Holds an error type, a 76 // message, and possibly additional information specific to that error. 77 // 78 // Doesn't contain anything beyond a type and message now, but will in the 79 // future as more errors are implemented. 80 class RTCError { 81 public: 82 // Constructors. 83 84 // Creates a "no error" error. RTCError()85 RTCError() {} RTCError(RTCErrorType type)86 explicit RTCError(RTCErrorType type) : type_(type) {} 87 // For performance, prefer using the constructor that takes a const char* if 88 // the message is a static string. RTCError(RTCErrorType type,const char * message)89 RTCError(RTCErrorType type, const char* message) 90 : type_(type), static_message_(message), have_string_message_(false) {} RTCError(RTCErrorType type,std::string && message)91 RTCError(RTCErrorType type, std::string&& message) 92 : type_(type), string_message_(message), have_string_message_(true) {} 93 94 // Delete the copy constructor and assignment operator; there aren't any use 95 // cases where you should need to copy an RTCError, as opposed to moving it. 96 // Can revisit this decision if use cases arise in the future. 97 RTCError(const RTCError& other) = delete; 98 RTCError& operator=(const RTCError& other) = delete; 99 100 // Move constructor and move-assignment operator. 101 RTCError(RTCError&& other); 102 RTCError& operator=(RTCError&& other); 103 104 ~RTCError(); 105 106 // Identical to default constructed error. 107 // 108 // Preferred over the default constructor for code readability. 109 static RTCError OK(); 110 111 // Error type. type()112 RTCErrorType type() const { return type_; } set_type(RTCErrorType type)113 void set_type(RTCErrorType type) { type_ = type; } 114 115 // Human-readable message describing the error. Shouldn't be used for 116 // anything but logging/diagnostics, since messages are not guaranteed to be 117 // stable. 118 const char* message() const; 119 // For performance, prefer using the method that takes a const char* if the 120 // message is a static string. 121 void set_message(const char* message); 122 void set_message(std::string&& message); 123 124 // Convenience method for situations where you only care whether or not an 125 // error occurred. ok()126 bool ok() const { return type_ == RTCErrorType::NONE; } 127 128 private: 129 RTCErrorType type_ = RTCErrorType::NONE; 130 // For performance, we use static strings wherever possible. But in some 131 // cases the error string may need to be constructed, in which case an 132 // std::string is used. 133 union { 134 const char* static_message_ = ""; 135 std::string string_message_; 136 }; 137 // Whether or not |static_message_| or |string_message_| is being used in the 138 // above union. 139 bool have_string_message_ = false; 140 }; 141 142 // Outputs the error as a friendly string. Update this method when adding a new 143 // error type. 144 // 145 // Only intended to be used for logging/disagnostics. 146 std::ostream& operator<<(std::ostream& stream, RTCErrorType error); 147 148 // Helper macro that can be used by implementations to create an error with a 149 // message and log it. |message| should be a string literal or movable 150 // std::string. 151 #define LOG_AND_RETURN_ERROR_EX(type, message, severity) \ 152 { \ 153 RTC_DCHECK(type != RTCErrorType::NONE); \ 154 RTC_LOG(severity) << message << " (" << type << ")"; \ 155 return webrtc::RTCError(type, message); \ 156 } 157 158 #define LOG_AND_RETURN_ERROR(type, message) \ 159 LOG_AND_RETURN_ERROR_EX(type, message, LS_ERROR) 160 161 // RTCErrorOr<T> is the union of an RTCError object and a T object. RTCErrorOr 162 // models the concept of an object that is either a usable value, or an error 163 // Status explaining why such a value is not present. To this end RTCErrorOr<T> 164 // does not allow its RTCErrorType value to be RTCErrorType::NONE. This is 165 // enforced by a debug check in most cases. 166 // 167 // The primary use-case for RTCErrorOr<T> is as the return value of a function 168 // which may fail. For example, CreateRtpSender will fail if the parameters 169 // could not be successfully applied at the media engine level, but if 170 // successful will return a unique_ptr to an RtpSender. 171 // 172 // Example client usage for a RTCErrorOr<std::unique_ptr<T>>: 173 // 174 // RTCErrorOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg); 175 // if (result.ok()) { 176 // std::unique_ptr<Foo> foo = result.ConsumeValue(); 177 // foo->DoSomethingCool(); 178 // } else { 179 // RTC_LOG(LS_ERROR) << result.error(); 180 // } 181 // 182 // Example factory implementation returning RTCErrorOr<std::unique_ptr<T>>: 183 // 184 // RTCErrorOr<std::unique_ptr<Foo>> FooFactory::MakeNewFoo(int arg) { 185 // if (arg <= 0) { 186 // return RTCError(RTCErrorType::INVALID_RANGE, "Arg must be positive"); 187 // } else { 188 // return std::unique_ptr<Foo>(new Foo(arg)); 189 // } 190 // } 191 // 192 template <typename T> 193 class RTCErrorOr { 194 // Used to convert between RTCErrorOr<Foo>/RtcErrorOr<Bar>, when an implicit 195 // conversion from Foo to Bar exists. 196 template <typename U> 197 friend class RTCErrorOr; 198 199 public: 200 typedef T element_type; 201 202 // Constructs a new RTCErrorOr with RTCErrorType::INTERNAL_ERROR error. This 203 // is marked 'explicit' to try to catch cases like 'return {};', where people 204 // think RTCErrorOr<std::vector<int>> will be initialized with an empty 205 // vector, instead of a RTCErrorType::INTERNAL_ERROR error. RTCErrorOr()206 RTCErrorOr() : error_(RTCErrorType::INTERNAL_ERROR) {} 207 208 // Constructs a new RTCErrorOr with the given non-ok error. After calling 209 // this constructor, calls to value() will DCHECK-fail. 210 // 211 // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return 212 // value, so it is convenient and sensible to be able to do 'return 213 // RTCError(...)' when the return type is RTCErrorOr<T>. 214 // 215 // REQUIRES: !error.ok(). This requirement is DCHECKed. RTCErrorOr(RTCError && error)216 RTCErrorOr(RTCError&& error) : error_(std::move(error)) { // NOLINT 217 RTC_DCHECK(!error.ok()); 218 } 219 220 // Constructs a new RTCErrorOr with the given value. After calling this 221 // constructor, calls to value() will succeed, and calls to error() will 222 // return a default-constructed RTCError. 223 // 224 // NOTE: Not explicit - we want to use RTCErrorOr<T> as a return type 225 // so it is convenient and sensible to be able to do 'return T()' 226 // when the return type is RTCErrorOr<T>. RTCErrorOr(T && value)227 RTCErrorOr(T&& value) : value_(std::move(value)) {} // NOLINT 228 229 // Delete the copy constructor and assignment operator; there aren't any use 230 // cases where you should need to copy an RTCErrorOr, as opposed to moving 231 // it. Can revisit this decision if use cases arise in the future. 232 RTCErrorOr(const RTCErrorOr& other) = delete; 233 RTCErrorOr& operator=(const RTCErrorOr& other) = delete; 234 235 // Move constructor and move-assignment operator. 236 // 237 // Visual Studio doesn't support "= default" with move constructors or 238 // assignment operators (even though they compile, they segfault), so define 239 // them explicitly. RTCErrorOr(RTCErrorOr && other)240 RTCErrorOr(RTCErrorOr&& other) 241 : error_(std::move(other.error_)), value_(std::move(other.value_)) {} 242 RTCErrorOr& operator=(RTCErrorOr&& other) { 243 error_ = std::move(other.error_); 244 value_ = std::move(other.value_); 245 return *this; 246 } 247 248 // Conversion constructor and assignment operator; T must be copy or move 249 // constructible from U. 250 template <typename U> RTCErrorOr(RTCErrorOr<U> other)251 RTCErrorOr(RTCErrorOr<U> other) // NOLINT 252 : error_(std::move(other.error_)), value_(std::move(other.value_)) {} 253 template <typename U> 254 RTCErrorOr& operator=(RTCErrorOr<U> other) { 255 error_ = std::move(other.error_); 256 value_ = std::move(other.value_); 257 return *this; 258 } 259 260 // Returns a reference to our error. If this contains a T, then returns 261 // default-constructed RTCError. error()262 const RTCError& error() const { return error_; } 263 264 // Moves the error. Can be useful if, say "CreateFoo" returns an 265 // RTCErrorOr<Foo>, and internally calls "CreateBar" which returns an 266 // RTCErrorOr<Bar>, and wants to forward the error up the stack. MoveError()267 RTCError MoveError() { return std::move(error_); } 268 269 // Returns this->error().ok() ok()270 bool ok() const { return error_.ok(); } 271 272 // Returns a reference to our current value, or DCHECK-fails if !this->ok(). 273 // 274 // Can be convenient for the implementation; for example, a method may want 275 // to access the value in some way before returning it to the next method on 276 // the stack. value()277 const T& value() const { 278 RTC_DCHECK(ok()); 279 return value_; 280 } value()281 T& value() { 282 RTC_DCHECK(ok()); 283 return value_; 284 } 285 286 // Moves our current value out of this object and returns it, or DCHECK-fails 287 // if !this->ok(). MoveValue()288 T MoveValue() { 289 RTC_DCHECK(ok()); 290 return std::move(value_); 291 } 292 293 private: 294 RTCError error_; 295 T value_; 296 }; 297 298 } // namespace webrtc 299 300 #endif // API_RTCERROR_H_ 301