xref: /aosp_15_r20/external/openscreen/platform/base/error.h (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2018 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #ifndef PLATFORM_BASE_ERROR_H_
6*3f982cf4SFabien Sanglard #define PLATFORM_BASE_ERROR_H_
7*3f982cf4SFabien Sanglard 
8*3f982cf4SFabien Sanglard #include <cassert>
9*3f982cf4SFabien Sanglard #include <ostream>
10*3f982cf4SFabien Sanglard #include <string>
11*3f982cf4SFabien Sanglard #include <utility>
12*3f982cf4SFabien Sanglard 
13*3f982cf4SFabien Sanglard #include "platform/base/macros.h"
14*3f982cf4SFabien Sanglard 
15*3f982cf4SFabien Sanglard namespace openscreen {
16*3f982cf4SFabien Sanglard 
17*3f982cf4SFabien Sanglard // Represents an error returned by an OSP library operation.  An error has a
18*3f982cf4SFabien Sanglard // code and an optional message.
19*3f982cf4SFabien Sanglard class Error {
20*3f982cf4SFabien Sanglard  public:
21*3f982cf4SFabien Sanglard   // TODO(crbug.com/openscreen/65): Group/rename OSP-specific errors
22*3f982cf4SFabien Sanglard   enum class Code : int8_t {
23*3f982cf4SFabien Sanglard     // No error occurred.
24*3f982cf4SFabien Sanglard     kNone = 0,
25*3f982cf4SFabien Sanglard 
26*3f982cf4SFabien Sanglard     // A transient condition prevented the operation from proceeding (e.g.,
27*3f982cf4SFabien Sanglard     // cannot send on a non-blocking socket without blocking). This indicates
28*3f982cf4SFabien Sanglard     // the caller should try again later.
29*3f982cf4SFabien Sanglard     kAgain = -1,
30*3f982cf4SFabien Sanglard 
31*3f982cf4SFabien Sanglard     // CBOR errors.
32*3f982cf4SFabien Sanglard     kCborParsing = 1,
33*3f982cf4SFabien Sanglard     kCborEncoding,
34*3f982cf4SFabien Sanglard     kCborIncompleteMessage,
35*3f982cf4SFabien Sanglard     kCborInvalidResponseId,
36*3f982cf4SFabien Sanglard     kCborInvalidMessage,
37*3f982cf4SFabien Sanglard 
38*3f982cf4SFabien Sanglard     // Presentation start errors.
39*3f982cf4SFabien Sanglard     kNoAvailableReceivers,
40*3f982cf4SFabien Sanglard     kRequestCancelled,
41*3f982cf4SFabien Sanglard     kNoPresentationFound,
42*3f982cf4SFabien Sanglard     kPreviousStartInProgress,
43*3f982cf4SFabien Sanglard     kUnknownStartError,
44*3f982cf4SFabien Sanglard     kUnknownRequestId,
45*3f982cf4SFabien Sanglard 
46*3f982cf4SFabien Sanglard     kAddressInUse,
47*3f982cf4SFabien Sanglard     kDomainNameTooLong,
48*3f982cf4SFabien Sanglard     kDomainNameLabelTooLong,
49*3f982cf4SFabien Sanglard 
50*3f982cf4SFabien Sanglard     kIOFailure,
51*3f982cf4SFabien Sanglard     kInitializationFailure,
52*3f982cf4SFabien Sanglard     kInvalidIPV4Address,
53*3f982cf4SFabien Sanglard     kInvalidIPV6Address,
54*3f982cf4SFabien Sanglard     kConnectionFailed,
55*3f982cf4SFabien Sanglard 
56*3f982cf4SFabien Sanglard     kSocketOptionSettingFailure,
57*3f982cf4SFabien Sanglard     kSocketAcceptFailure,
58*3f982cf4SFabien Sanglard     kSocketBindFailure,
59*3f982cf4SFabien Sanglard     kSocketClosedFailure,
60*3f982cf4SFabien Sanglard     kSocketConnectFailure,
61*3f982cf4SFabien Sanglard     kSocketInvalidState,
62*3f982cf4SFabien Sanglard     kSocketListenFailure,
63*3f982cf4SFabien Sanglard     kSocketReadFailure,
64*3f982cf4SFabien Sanglard     kSocketSendFailure,
65*3f982cf4SFabien Sanglard 
66*3f982cf4SFabien Sanglard     // MDNS errors.
67*3f982cf4SFabien Sanglard     kMdnsRegisterFailure,
68*3f982cf4SFabien Sanglard     kMdnsReadFailure,
69*3f982cf4SFabien Sanglard     kMdnsNonConformingFailure,
70*3f982cf4SFabien Sanglard 
71*3f982cf4SFabien Sanglard     kParseError,
72*3f982cf4SFabien Sanglard     kUnknownMessageType,
73*3f982cf4SFabien Sanglard 
74*3f982cf4SFabien Sanglard     kNoActiveConnection,
75*3f982cf4SFabien Sanglard     kAlreadyClosed,
76*3f982cf4SFabien Sanglard     kInvalidConnectionState,
77*3f982cf4SFabien Sanglard     kNoStartedPresentation,
78*3f982cf4SFabien Sanglard     kPresentationAlreadyStarted,
79*3f982cf4SFabien Sanglard 
80*3f982cf4SFabien Sanglard     kJsonParseError,
81*3f982cf4SFabien Sanglard     kJsonWriteError,
82*3f982cf4SFabien Sanglard 
83*3f982cf4SFabien Sanglard     // OpenSSL errors.
84*3f982cf4SFabien Sanglard 
85*3f982cf4SFabien Sanglard     // Was unable to generate an RSA key.
86*3f982cf4SFabien Sanglard     kRSAKeyGenerationFailure,
87*3f982cf4SFabien Sanglard     kRSAKeyParseError,
88*3f982cf4SFabien Sanglard 
89*3f982cf4SFabien Sanglard     // Was unable to initialize an EVP_PKEY type.
90*3f982cf4SFabien Sanglard     kEVPInitializationError,
91*3f982cf4SFabien Sanglard 
92*3f982cf4SFabien Sanglard     // Was unable to generate a certificate.
93*3f982cf4SFabien Sanglard     kCertificateCreationError,
94*3f982cf4SFabien Sanglard 
95*3f982cf4SFabien Sanglard     // Certificate failed validation.
96*3f982cf4SFabien Sanglard     kCertificateValidationError,
97*3f982cf4SFabien Sanglard 
98*3f982cf4SFabien Sanglard     // Failed to produce a hashing digest.
99*3f982cf4SFabien Sanglard     kSha256HashFailure,
100*3f982cf4SFabien Sanglard 
101*3f982cf4SFabien Sanglard     // A non-recoverable SSL library error has occurred.
102*3f982cf4SFabien Sanglard     kFatalSSLError,
103*3f982cf4SFabien Sanglard     kFileLoadFailure,
104*3f982cf4SFabien Sanglard 
105*3f982cf4SFabien Sanglard     // Cast certificate errors.
106*3f982cf4SFabien Sanglard 
107*3f982cf4SFabien Sanglard     // Certificates were not provided for verification.
108*3f982cf4SFabien Sanglard     kErrCertsMissing,
109*3f982cf4SFabien Sanglard 
110*3f982cf4SFabien Sanglard     // The certificates provided could not be parsed.
111*3f982cf4SFabien Sanglard     kErrCertsParse,
112*3f982cf4SFabien Sanglard 
113*3f982cf4SFabien Sanglard     // Key usage is missing or is not set to Digital Signature.
114*3f982cf4SFabien Sanglard     // This error could also be thrown if the CN is missing.
115*3f982cf4SFabien Sanglard     kErrCertsRestrictions,
116*3f982cf4SFabien Sanglard 
117*3f982cf4SFabien Sanglard     // The current date is before the notBefore date or after the notAfter date.
118*3f982cf4SFabien Sanglard     kErrCertsDateInvalid,
119*3f982cf4SFabien Sanglard 
120*3f982cf4SFabien Sanglard     // The certificate failed to chain to a trusted root.
121*3f982cf4SFabien Sanglard     kErrCertsVerifyGeneric,
122*3f982cf4SFabien Sanglard 
123*3f982cf4SFabien Sanglard     // The certificate was not found in the trust store.
124*3f982cf4SFabien Sanglard     kErrCertsVerifyUntrustedCert,
125*3f982cf4SFabien Sanglard 
126*3f982cf4SFabien Sanglard     // The CRL is missing or failed to verify.
127*3f982cf4SFabien Sanglard     kErrCrlInvalid,
128*3f982cf4SFabien Sanglard 
129*3f982cf4SFabien Sanglard     // One of the certificates in the chain is revoked.
130*3f982cf4SFabien Sanglard     kErrCertsRevoked,
131*3f982cf4SFabien Sanglard 
132*3f982cf4SFabien Sanglard     // The pathlen constraint of the root certificate was exceeded.
133*3f982cf4SFabien Sanglard     kErrCertsPathlen,
134*3f982cf4SFabien Sanglard 
135*3f982cf4SFabien Sanglard     // Cast authentication errors.
136*3f982cf4SFabien Sanglard     kCastV2PeerCertEmpty,
137*3f982cf4SFabien Sanglard     kCastV2WrongPayloadType,
138*3f982cf4SFabien Sanglard     kCastV2NoPayload,
139*3f982cf4SFabien Sanglard     kCastV2PayloadParsingFailed,
140*3f982cf4SFabien Sanglard     kCastV2MessageError,
141*3f982cf4SFabien Sanglard     kCastV2NoResponse,
142*3f982cf4SFabien Sanglard     kCastV2FingerprintNotFound,
143*3f982cf4SFabien Sanglard     kCastV2CertNotSignedByTrustedCa,
144*3f982cf4SFabien Sanglard     kCastV2CannotExtractPublicKey,
145*3f982cf4SFabien Sanglard     kCastV2SignedBlobsMismatch,
146*3f982cf4SFabien Sanglard     kCastV2TlsCertValidityPeriodTooLong,
147*3f982cf4SFabien Sanglard     kCastV2TlsCertValidStartDateInFuture,
148*3f982cf4SFabien Sanglard     kCastV2TlsCertExpired,
149*3f982cf4SFabien Sanglard     kCastV2SenderNonceMismatch,
150*3f982cf4SFabien Sanglard     kCastV2DigestUnsupported,
151*3f982cf4SFabien Sanglard     kCastV2SignatureEmpty,
152*3f982cf4SFabien Sanglard 
153*3f982cf4SFabien Sanglard     // Cast channel errors.
154*3f982cf4SFabien Sanglard     kCastV2ChannelNotOpen,
155*3f982cf4SFabien Sanglard     kCastV2AuthenticationError,
156*3f982cf4SFabien Sanglard     kCastV2ConnectError,
157*3f982cf4SFabien Sanglard     kCastV2CastSocketError,
158*3f982cf4SFabien Sanglard     kCastV2TransportError,
159*3f982cf4SFabien Sanglard     kCastV2InvalidMessage,
160*3f982cf4SFabien Sanglard     kCastV2InvalidChannelId,
161*3f982cf4SFabien Sanglard     kCastV2ConnectTimeout,
162*3f982cf4SFabien Sanglard     kCastV2PingTimeout,
163*3f982cf4SFabien Sanglard     kCastV2ChannelPolicyMismatch,
164*3f982cf4SFabien Sanglard 
165*3f982cf4SFabien Sanglard     kCreateSignatureFailed,
166*3f982cf4SFabien Sanglard 
167*3f982cf4SFabien Sanglard     // Discovery errors.
168*3f982cf4SFabien Sanglard     kUpdateReceivedRecordFailure,
169*3f982cf4SFabien Sanglard     kRecordPublicationError,
170*3f982cf4SFabien Sanglard     kProcessReceivedRecordFailure,
171*3f982cf4SFabien Sanglard 
172*3f982cf4SFabien Sanglard     // Generic errors.
173*3f982cf4SFabien Sanglard     kUnknownError,
174*3f982cf4SFabien Sanglard     kNotImplemented,
175*3f982cf4SFabien Sanglard     kInsufficientBuffer,
176*3f982cf4SFabien Sanglard     kParameterInvalid,
177*3f982cf4SFabien Sanglard     kParameterOutOfRange,
178*3f982cf4SFabien Sanglard     kParameterNullPointer,
179*3f982cf4SFabien Sanglard     kIndexOutOfBounds,
180*3f982cf4SFabien Sanglard     kItemAlreadyExists,
181*3f982cf4SFabien Sanglard     kItemNotFound,
182*3f982cf4SFabien Sanglard     kOperationInvalid,
183*3f982cf4SFabien Sanglard     kOperationInProgress,
184*3f982cf4SFabien Sanglard     kOperationCancelled,
185*3f982cf4SFabien Sanglard 
186*3f982cf4SFabien Sanglard     // Cast streaming errors
187*3f982cf4SFabien Sanglard     kTypeError,
188*3f982cf4SFabien Sanglard     kUnknownCodec,
189*3f982cf4SFabien Sanglard     kInvalidCodecParameter,
190*3f982cf4SFabien Sanglard     kSocketFailure,
191*3f982cf4SFabien Sanglard     kUnencryptedOffer,
192*3f982cf4SFabien Sanglard     kRemotingNotSupported,
193*3f982cf4SFabien Sanglard 
194*3f982cf4SFabien Sanglard     // A negotiation failure means that the current negotiation must be
195*3f982cf4SFabien Sanglard     // restarted by the sender.
196*3f982cf4SFabien Sanglard     kNegotiationFailure,
197*3f982cf4SFabien Sanglard   };
198*3f982cf4SFabien Sanglard 
199*3f982cf4SFabien Sanglard   Error();
200*3f982cf4SFabien Sanglard   Error(const Error& error);
201*3f982cf4SFabien Sanglard   Error(Error&& error) noexcept;
202*3f982cf4SFabien Sanglard 
203*3f982cf4SFabien Sanglard   Error(Code code);  // NOLINT
204*3f982cf4SFabien Sanglard   Error(Code code, const std::string& message);
205*3f982cf4SFabien Sanglard   Error(Code code, std::string&& message);
206*3f982cf4SFabien Sanglard   ~Error();
207*3f982cf4SFabien Sanglard 
208*3f982cf4SFabien Sanglard   Error& operator=(const Error& other);
209*3f982cf4SFabien Sanglard   Error& operator=(Error&& other);
210*3f982cf4SFabien Sanglard   bool operator==(const Error& other) const;
211*3f982cf4SFabien Sanglard   bool operator!=(const Error& other) const;
212*3f982cf4SFabien Sanglard 
213*3f982cf4SFabien Sanglard   // Special case comparison with codes. Without this case, comparisons will
214*3f982cf4SFabien Sanglard   // not work as expected, e.g.
215*3f982cf4SFabien Sanglard   // const Error foo(Error::Code::kItemNotFound, "Didn't find an item");
216*3f982cf4SFabien Sanglard   // foo == Error::Code::kItemNotFound is actually false.
217*3f982cf4SFabien Sanglard   bool operator==(Code code) const;
218*3f982cf4SFabien Sanglard   bool operator!=(Code code) const;
ok()219*3f982cf4SFabien Sanglard   bool ok() const { return code_ == Code::kNone; }
220*3f982cf4SFabien Sanglard 
code()221*3f982cf4SFabien Sanglard   Code code() const { return code_; }
message()222*3f982cf4SFabien Sanglard   const std::string& message() const { return message_; }
message()223*3f982cf4SFabien Sanglard   std::string& message() { return message_; }
224*3f982cf4SFabien Sanglard 
225*3f982cf4SFabien Sanglard   static const Error& None();
226*3f982cf4SFabien Sanglard 
227*3f982cf4SFabien Sanglard   std::string ToString() const;
228*3f982cf4SFabien Sanglard 
229*3f982cf4SFabien Sanglard  private:
230*3f982cf4SFabien Sanglard   Code code_ = Code::kNone;
231*3f982cf4SFabien Sanglard   std::string message_;
232*3f982cf4SFabien Sanglard };
233*3f982cf4SFabien Sanglard 
234*3f982cf4SFabien Sanglard std::ostream& operator<<(std::ostream& os, const Error::Code& code);
235*3f982cf4SFabien Sanglard 
236*3f982cf4SFabien Sanglard std::ostream& operator<<(std::ostream& out, const Error& error);
237*3f982cf4SFabien Sanglard 
238*3f982cf4SFabien Sanglard // A convenience function to return a single value from a function that can
239*3f982cf4SFabien Sanglard // return a value or an error.  For normal results, construct with a ValueType*
240*3f982cf4SFabien Sanglard // (ErrorOr takes ownership) and the Error will be kNone with an empty message.
241*3f982cf4SFabien Sanglard // For Error results, construct with an error code and value.
242*3f982cf4SFabien Sanglard //
243*3f982cf4SFabien Sanglard // Example:
244*3f982cf4SFabien Sanglard //
245*3f982cf4SFabien Sanglard // ErrorOr<Bar> Foo::DoSomething() {
246*3f982cf4SFabien Sanglard //   if (success) {
247*3f982cf4SFabien Sanglard //     return Bar();
248*3f982cf4SFabien Sanglard //   } else {
249*3f982cf4SFabien Sanglard //     return Error(kBadThingHappened, "No can do");
250*3f982cf4SFabien Sanglard //   }
251*3f982cf4SFabien Sanglard // }
252*3f982cf4SFabien Sanglard //
253*3f982cf4SFabien Sanglard // TODO(mfoltz): Add support for type conversions.
254*3f982cf4SFabien Sanglard template <typename ValueType>
255*3f982cf4SFabien Sanglard class ErrorOr {
256*3f982cf4SFabien Sanglard  public:
None()257*3f982cf4SFabien Sanglard   static ErrorOr<ValueType> None() {
258*3f982cf4SFabien Sanglard     static ErrorOr<ValueType> error(Error::Code::kNone);
259*3f982cf4SFabien Sanglard     return error;
260*3f982cf4SFabien Sanglard   }
261*3f982cf4SFabien Sanglard 
ErrorOr(const ValueType & value)262*3f982cf4SFabien Sanglard   ErrorOr(const ValueType& value) : value_(value), is_value_(true) {}  // NOLINT
ErrorOr(ValueType && value)263*3f982cf4SFabien Sanglard   ErrorOr(ValueType&& value) noexcept                                  // NOLINT
264*3f982cf4SFabien Sanglard       : value_(std::move(value)), is_value_(true) {}
265*3f982cf4SFabien Sanglard 
ErrorOr(const Error & error)266*3f982cf4SFabien Sanglard   ErrorOr(const Error& error) : error_(error), is_value_(false) {  // NOLINT
267*3f982cf4SFabien Sanglard     assert(error_.code() != Error::Code::kNone);
268*3f982cf4SFabien Sanglard   }
ErrorOr(Error && error)269*3f982cf4SFabien Sanglard   ErrorOr(Error&& error) noexcept  // NOLINT
270*3f982cf4SFabien Sanglard       : error_(std::move(error)), is_value_(false) {
271*3f982cf4SFabien Sanglard     assert(error_.code() != Error::Code::kNone);
272*3f982cf4SFabien Sanglard   }
ErrorOr(Error::Code code)273*3f982cf4SFabien Sanglard   ErrorOr(Error::Code code) : error_(code), is_value_(false) {  // NOLINT
274*3f982cf4SFabien Sanglard     assert(error_.code() != Error::Code::kNone);
275*3f982cf4SFabien Sanglard   }
ErrorOr(Error::Code code,std::string message)276*3f982cf4SFabien Sanglard   ErrorOr(Error::Code code, std::string message)
277*3f982cf4SFabien Sanglard       : error_(code, std::move(message)), is_value_(false) {
278*3f982cf4SFabien Sanglard     assert(error_.code() != Error::Code::kNone);
279*3f982cf4SFabien Sanglard   }
280*3f982cf4SFabien Sanglard 
281*3f982cf4SFabien Sanglard   ErrorOr(const ErrorOr& other) = delete;
ErrorOr(ErrorOr && other)282*3f982cf4SFabien Sanglard   ErrorOr(ErrorOr&& other) noexcept : is_value_(other.is_value_) {
283*3f982cf4SFabien Sanglard     // NB: Both |value_| and |error_| are uninitialized memory at this point!
284*3f982cf4SFabien Sanglard     // Unlike the other constructors, the compiler will not auto-generate
285*3f982cf4SFabien Sanglard     // constructor calls for either union member because neither appeared in
286*3f982cf4SFabien Sanglard     // this constructor's initializer list.
287*3f982cf4SFabien Sanglard     if (other.is_value_) {
288*3f982cf4SFabien Sanglard       new (&value_) ValueType(std::move(other.value_));
289*3f982cf4SFabien Sanglard     } else {
290*3f982cf4SFabien Sanglard       new (&error_) Error(std::move(other.error_));
291*3f982cf4SFabien Sanglard     }
292*3f982cf4SFabien Sanglard   }
293*3f982cf4SFabien Sanglard 
294*3f982cf4SFabien Sanglard   ErrorOr& operator=(const ErrorOr& other) = delete;
295*3f982cf4SFabien Sanglard   ErrorOr& operator=(ErrorOr&& other) noexcept {
296*3f982cf4SFabien Sanglard     this->~ErrorOr<ValueType>();
297*3f982cf4SFabien Sanglard     new (this) ErrorOr<ValueType>(std::move(other));
298*3f982cf4SFabien Sanglard     return *this;
299*3f982cf4SFabien Sanglard   }
300*3f982cf4SFabien Sanglard 
~ErrorOr()301*3f982cf4SFabien Sanglard   ~ErrorOr() {
302*3f982cf4SFabien Sanglard     // NB: |value_| or |error_| must be explicitly destroyed since the compiler
303*3f982cf4SFabien Sanglard     // will not auto-generate the destructor calls for union members.
304*3f982cf4SFabien Sanglard     if (is_value_) {
305*3f982cf4SFabien Sanglard       value_.~ValueType();
306*3f982cf4SFabien Sanglard     } else {
307*3f982cf4SFabien Sanglard       error_.~Error();
308*3f982cf4SFabien Sanglard     }
309*3f982cf4SFabien Sanglard   }
310*3f982cf4SFabien Sanglard 
is_error()311*3f982cf4SFabien Sanglard   bool is_error() const { return !is_value_; }
is_value()312*3f982cf4SFabien Sanglard   bool is_value() const { return is_value_; }
313*3f982cf4SFabien Sanglard 
314*3f982cf4SFabien Sanglard   // Unlike Error, we CAN provide an operator bool here, since it is
315*3f982cf4SFabien Sanglard   // more obvious to callers that ErrorOr<Foo> will be true if it's Foo.
316*3f982cf4SFabien Sanglard   operator bool() const { return is_value_; }
317*3f982cf4SFabien Sanglard 
error()318*3f982cf4SFabien Sanglard   const Error& error() const {
319*3f982cf4SFabien Sanglard     assert(!is_value_);
320*3f982cf4SFabien Sanglard     return error_;
321*3f982cf4SFabien Sanglard   }
error()322*3f982cf4SFabien Sanglard   Error& error() {
323*3f982cf4SFabien Sanglard     assert(!is_value_);
324*3f982cf4SFabien Sanglard     return error_;
325*3f982cf4SFabien Sanglard   }
326*3f982cf4SFabien Sanglard 
value()327*3f982cf4SFabien Sanglard   const ValueType& value() const {
328*3f982cf4SFabien Sanglard     assert(is_value_);
329*3f982cf4SFabien Sanglard     return value_;
330*3f982cf4SFabien Sanglard   }
value()331*3f982cf4SFabien Sanglard   ValueType& value() {
332*3f982cf4SFabien Sanglard     assert(is_value_);
333*3f982cf4SFabien Sanglard     return value_;
334*3f982cf4SFabien Sanglard   }
335*3f982cf4SFabien Sanglard 
336*3f982cf4SFabien Sanglard   // Move only value or fallback
value(ValueType && fallback)337*3f982cf4SFabien Sanglard   ValueType&& value(ValueType&& fallback) {
338*3f982cf4SFabien Sanglard     if (is_value()) {
339*3f982cf4SFabien Sanglard       return std::move(value());
340*3f982cf4SFabien Sanglard     }
341*3f982cf4SFabien Sanglard     return std::forward<ValueType>(fallback);
342*3f982cf4SFabien Sanglard   }
343*3f982cf4SFabien Sanglard 
344*3f982cf4SFabien Sanglard   // Copy only value or fallback
value(ValueType fallback)345*3f982cf4SFabien Sanglard   ValueType value(ValueType fallback) const {
346*3f982cf4SFabien Sanglard     if (is_value()) {
347*3f982cf4SFabien Sanglard       return value();
348*3f982cf4SFabien Sanglard     }
349*3f982cf4SFabien Sanglard     return std::move(fallback);
350*3f982cf4SFabien Sanglard   }
351*3f982cf4SFabien Sanglard 
352*3f982cf4SFabien Sanglard  private:
353*3f982cf4SFabien Sanglard   // Only one of these is an active member, determined by |is_value_|. Since
354*3f982cf4SFabien Sanglard   // they are union'ed, they must be explicitly constructed and destroyed.
355*3f982cf4SFabien Sanglard   union {
356*3f982cf4SFabien Sanglard     ValueType value_;
357*3f982cf4SFabien Sanglard     Error error_;
358*3f982cf4SFabien Sanglard   };
359*3f982cf4SFabien Sanglard 
360*3f982cf4SFabien Sanglard   // If true, |value_| is initialized and active. Otherwise, |error_| is
361*3f982cf4SFabien Sanglard   // initialized and active.
362*3f982cf4SFabien Sanglard   const bool is_value_;
363*3f982cf4SFabien Sanglard };
364*3f982cf4SFabien Sanglard 
365*3f982cf4SFabien Sanglard // Define comparison operators using SFINAE.
366*3f982cf4SFabien Sanglard template <typename ValueType>
367*3f982cf4SFabien Sanglard bool operator<(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
368*3f982cf4SFabien Sanglard   // Handle the cases where one side is an error.
369*3f982cf4SFabien Sanglard   if (lhs.is_error() != rhs.is_error()) {
370*3f982cf4SFabien Sanglard     return lhs.is_error();
371*3f982cf4SFabien Sanglard   }
372*3f982cf4SFabien Sanglard 
373*3f982cf4SFabien Sanglard   // Handle the case where both sides are errors.
374*3f982cf4SFabien Sanglard   if (lhs.is_error()) {
375*3f982cf4SFabien Sanglard     return static_cast<int8_t>(lhs.error().code()) <
376*3f982cf4SFabien Sanglard            static_cast<int8_t>(rhs.error().code());
377*3f982cf4SFabien Sanglard   }
378*3f982cf4SFabien Sanglard 
379*3f982cf4SFabien Sanglard   // Handle the case where both are values.
380*3f982cf4SFabien Sanglard   return lhs.value() < rhs.value();
381*3f982cf4SFabien Sanglard }
382*3f982cf4SFabien Sanglard 
383*3f982cf4SFabien Sanglard template <typename ValueType>
384*3f982cf4SFabien Sanglard bool operator>(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
385*3f982cf4SFabien Sanglard   return rhs < lhs;
386*3f982cf4SFabien Sanglard }
387*3f982cf4SFabien Sanglard 
388*3f982cf4SFabien Sanglard template <typename ValueType>
389*3f982cf4SFabien Sanglard bool operator<=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
390*3f982cf4SFabien Sanglard   return !(lhs > rhs);
391*3f982cf4SFabien Sanglard }
392*3f982cf4SFabien Sanglard 
393*3f982cf4SFabien Sanglard template <typename ValueType>
394*3f982cf4SFabien Sanglard bool operator>=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
395*3f982cf4SFabien Sanglard   return !(rhs < lhs);
396*3f982cf4SFabien Sanglard }
397*3f982cf4SFabien Sanglard 
398*3f982cf4SFabien Sanglard template <typename ValueType>
399*3f982cf4SFabien Sanglard bool operator==(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
400*3f982cf4SFabien Sanglard   // Handle the cases where one side is an error.
401*3f982cf4SFabien Sanglard   if (lhs.is_error() != rhs.is_error()) {
402*3f982cf4SFabien Sanglard     return false;
403*3f982cf4SFabien Sanglard   }
404*3f982cf4SFabien Sanglard 
405*3f982cf4SFabien Sanglard   // Handle the case where both sides are errors.
406*3f982cf4SFabien Sanglard   if (lhs.is_error()) {
407*3f982cf4SFabien Sanglard     return lhs.error() == rhs.error();
408*3f982cf4SFabien Sanglard   }
409*3f982cf4SFabien Sanglard 
410*3f982cf4SFabien Sanglard   // Handle the case where both are values.
411*3f982cf4SFabien Sanglard   return lhs.value() == rhs.value();
412*3f982cf4SFabien Sanglard }
413*3f982cf4SFabien Sanglard 
414*3f982cf4SFabien Sanglard template <typename ValueType>
415*3f982cf4SFabien Sanglard bool operator!=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
416*3f982cf4SFabien Sanglard   return !(lhs == rhs);
417*3f982cf4SFabien Sanglard }
418*3f982cf4SFabien Sanglard 
419*3f982cf4SFabien Sanglard }  // namespace openscreen
420*3f982cf4SFabien Sanglard 
421*3f982cf4SFabien Sanglard #endif  // PLATFORM_BASE_ERROR_H_
422