1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* A type suitable for returning either a value or an error from a function. */
9 #ifndef mozilla_Result_h
10 #define mozilla_Result_h
12 #include <type_traits>
13 #include "mozilla/Alignment.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Attributes.h"
16 #include "mozilla/Types.h"
17 #include "mozilla/TypeTraits.h"
18 #include "mozilla/Variant.h"
23 * Empty struct, indicating success for operations that have no return value.
24 * For example, if you declare another empty struct `struct OutOfMemory {};`,
25 * then `Result<Ok, OutOfMemory>` represents either success or OOM.
30 class GenericErrorResult
;
31 template <typename V
, typename E
>
36 enum class PackingStrategy
{
43 template <typename V
, typename E
, PackingStrategy Strategy
>
44 class ResultImplementation
;
46 template <typename V
, typename E
>
47 class ResultImplementation
<V
, E
, PackingStrategy::Variant
> {
48 mozilla::Variant
<V
, E
> mStorage
;
51 ResultImplementation(ResultImplementation
&&) = default;
52 ResultImplementation(const ResultImplementation
&) = default;
53 ResultImplementation
& operator=(const ResultImplementation
&) = default;
54 ResultImplementation
& operator=(ResultImplementation
&&) = default;
56 explicit ResultImplementation(V
&& aValue
)
57 : mStorage(std::forward
<V
>(aValue
)) {}
58 explicit ResultImplementation(const V
& aValue
) : mStorage(aValue
) {}
59 explicit ResultImplementation(E aErrorValue
)
60 : mStorage(std::forward
<E
>(aErrorValue
)) {}
62 bool isOk() const { return mStorage
.template is
<V
>(); }
64 // The callers of these functions will assert isOk() has the proper value, so
65 // these functions (in all ResultImplementation specializations) don't need
67 V
unwrap() { return std::move(mStorage
.template as
<V
>()); }
68 const V
& inspect() const { return mStorage
.template as
<V
>(); }
70 E
unwrapErr() { return std::move(mStorage
.template as
<E
>()); }
71 const E
& inspectErr() const { return mStorage
.template as
<E
>(); }
75 * mozilla::Variant doesn't like storing a reference. This is a specialization
76 * to store E as pointer if it's a reference.
78 template <typename V
, typename E
>
79 class ResultImplementation
<V
, E
&, PackingStrategy::Variant
> {
80 mozilla::Variant
<V
, E
*> mStorage
;
83 explicit ResultImplementation(V
&& aValue
)
84 : mStorage(std::forward
<V
>(aValue
)) {}
85 explicit ResultImplementation(const V
& aValue
) : mStorage(aValue
) {}
86 explicit ResultImplementation(E
& aErrorValue
) : mStorage(&aErrorValue
) {}
88 bool isOk() const { return mStorage
.template is
<V
>(); }
90 const V
& inspect() const { return mStorage
.template as
<V
>(); }
91 V
unwrap() { return std::move(mStorage
.template as
<V
>()); }
93 E
& unwrapErr() { return *mStorage
.template as
<E
*>(); }
94 const E
& inspectErr() const { return *mStorage
.template as
<E
*>(); }
98 * Specialization for when the success type is Ok (or another empty class) and
99 * the error type is a reference.
101 template <typename V
, typename E
>
102 class ResultImplementation
<V
, E
&, PackingStrategy::NullIsOk
> {
106 explicit ResultImplementation(V
) : mErrorValue(nullptr) {}
107 explicit ResultImplementation(E
& aErrorValue
) : mErrorValue(&aErrorValue
) {}
109 bool isOk() const { return mErrorValue
== nullptr; }
111 const V
& inspect() const = delete;
112 V
unwrap() { return V(); }
114 const E
& inspectErr() const { return *mErrorValue
; }
115 E
& unwrapErr() { return *mErrorValue
; }
119 * Specialization for when the success type is Ok (or another empty class) and
120 * the error type is a value type which can never have the value 0 (as
121 * determined by UnusedZero<>).
123 template <typename V
, typename E
>
124 class ResultImplementation
<V
, E
, PackingStrategy::NullIsOk
> {
125 static constexpr E NullValue
= E(0);
130 explicit ResultImplementation(V
) : mErrorValue(NullValue
) {}
131 explicit ResultImplementation(E aErrorValue
) : mErrorValue(aErrorValue
) {
132 MOZ_ASSERT(aErrorValue
!= NullValue
);
135 bool isOk() const { return mErrorValue
== NullValue
; }
137 const V
& inspect() const = delete;
138 V
unwrap() { return V(); }
140 const E
& inspectErr() const { return mErrorValue
; }
141 E
unwrapErr() { return std::move(mErrorValue
); }
145 * Specialization for when alignment permits using the least significant bit as
148 template <typename V
, typename E
>
149 class ResultImplementation
<V
*, E
&, PackingStrategy::LowBitTagIsError
> {
153 explicit ResultImplementation(V
* aValue
)
154 : mBits(reinterpret_cast<uintptr_t>(aValue
)) {
155 MOZ_ASSERT((uintptr_t(aValue
) % MOZ_ALIGNOF(V
)) == 0,
156 "Result value pointers must not be misaligned");
158 explicit ResultImplementation(E
& aErrorValue
)
159 : mBits(reinterpret_cast<uintptr_t>(&aErrorValue
) | 1) {
160 MOZ_ASSERT((uintptr_t(&aErrorValue
) % MOZ_ALIGNOF(E
)) == 0,
161 "Result errors must not be misaligned");
164 bool isOk() const { return (mBits
& 1) == 0; }
166 V
* inspect() const { return reinterpret_cast<V
*>(mBits
); }
167 V
* unwrap() { return inspect(); }
169 E
& inspectErr() const { return *reinterpret_cast<E
*>(mBits
^ 1); }
170 E
& unwrapErr() { return inspectErr(); }
173 // Return true if any of the struct can fit in a word.
174 template <typename V
, typename E
>
175 struct IsPackableVariant
{
187 using Impl
= typename Conditional
<sizeof(VEbool
) <= sizeof(EVbool
), VEbool
,
190 static const bool value
= sizeof(Impl
) <= sizeof(uintptr_t);
194 * Specialization for when both type are not using all the bytes, in order to
195 * use one byte as a tag.
197 template <typename V
, typename E
>
198 class ResultImplementation
<V
, E
, PackingStrategy::PackedVariant
> {
199 using Impl
= typename IsPackableVariant
<V
, E
>::Impl
;
203 explicit ResultImplementation(V aValue
) {
204 data
.v
= std::move(aValue
);
207 explicit ResultImplementation(E aErrorValue
) {
208 data
.e
= std::move(aErrorValue
);
212 bool isOk() const { return data
.ok
; }
214 const V
& inspect() const { return data
.v
; }
215 V
unwrap() { return std::move(data
.v
); }
217 const E
& inspectErr() const { return data
.e
; }
218 E
unwrapErr() { return std::move(data
.e
); }
221 // To use nullptr as a special value, we need the counter part to exclude zero
222 // from its range of valid representations.
224 // By default assume that zero can be represented.
225 template <typename T
>
227 static const bool value
= false;
230 // References can't be null.
231 template <typename T
>
232 struct UnusedZero
<T
&> {
233 static const bool value
= true;
236 // A bit of help figuring out which of the above specializations to use.
238 // We begin by safely assuming types don't have a spare bit.
239 template <typename T
>
241 static const bool value
= false;
244 // As an incomplete type, void* does not have a spare bit.
246 struct HasFreeLSB
<void*> {
247 static const bool value
= false;
250 // The lowest bit of a properly-aligned pointer is always zero if the pointee
251 // type is greater than byte-aligned. That bit is free to use if it's masked
252 // out of such pointers before they're dereferenced.
253 template <typename T
>
254 struct HasFreeLSB
<T
*> {
255 static const bool value
= (alignof(T
) & 1) == 0;
258 // We store references as pointers, so they have a free bit if a pointer would
260 template <typename T
>
261 struct HasFreeLSB
<T
&> {
262 static const bool value
= HasFreeLSB
<T
*>::value
;
265 // Select one of the previous result implementation based on the properties of
266 // the V and E types.
267 template <typename V
, typename E
>
268 struct SelectResultImpl
{
269 static const PackingStrategy value
=
270 (IsEmpty
<V
>::value
&& UnusedZero
<E
>::value
)
271 ? PackingStrategy::NullIsOk
272 : (detail::HasFreeLSB
<V
>::value
&& detail::HasFreeLSB
<E
>::value
)
273 ? PackingStrategy::LowBitTagIsError
274 : (IsDefaultConstructible
<V
>::value
&&
275 IsDefaultConstructible
<E
>::value
&&
276 IsPackableVariant
<V
, E
>::value
)
277 ? PackingStrategy::PackedVariant
278 : PackingStrategy::Variant
;
280 using Type
= detail::ResultImplementation
<V
, E
, value
>;
283 template <typename T
>
284 struct IsResult
: FalseType
{};
286 template <typename V
, typename E
>
287 struct IsResult
<Result
<V
, E
>> : TrueType
{};
289 } // namespace detail
291 template <typename V
, typename E
>
292 auto ToResult(Result
<V
, E
>&& aValue
)
293 -> decltype(std::forward
<Result
<V
, E
>>(aValue
)) {
294 return std::forward
<Result
<V
, E
>>(aValue
);
298 * Result<V, E> represents the outcome of an operation that can either succeed
299 * or fail. It contains either a success value of type V or an error value of
302 * All Result methods are const, so results are basically immutable.
303 * This is just like Variant<V, E> but with a slightly different API, and the
304 * following cases are optimized so Result can be stored more efficiently:
306 * - If the success type is Ok (or another empty class) and the error type is a
307 * reference, Result<V, E&> is guaranteed to be pointer-sized and all zero
308 * bits on success. Do not change this representation! There is JIT code that
311 * - If the success type is a pointer type and the error type is a reference
312 * type, and the least significant bit is unused for both types when stored
313 * as a pointer (due to alignment rules), Result<V*, E&> is guaranteed to be
314 * pointer-sized. In this case, we use the lowest bit as tag bit: 0 to
315 * indicate the Result's bits are a V, 1 to indicate the Result's bits (with
316 * the 1 masked out) encode an E*.
318 * The purpose of Result is to reduce the screwups caused by using `false` or
319 * `nullptr` to indicate errors.
320 * What screwups? See <https://bugzilla.mozilla.org/show_bug.cgi?id=912928> for
323 template <typename V
, typename E
>
324 class MOZ_MUST_USE_TYPE Result final
{
325 using Impl
= typename
detail::SelectResultImpl
<V
, E
>::Type
;
330 /** Create a success result. */
331 MOZ_IMPLICIT
Result(V
&& aValue
) : mImpl(std::forward
<V
>(aValue
)) {
335 /** Create a success result. */
336 MOZ_IMPLICIT
Result(const V
& aValue
) : mImpl(aValue
) { MOZ_ASSERT(isOk()); }
338 /** Create an error result. */
339 explicit Result(E aErrorValue
) : mImpl(std::forward
<E
>(aErrorValue
)) {
344 * Implementation detail of MOZ_TRY().
345 * Create an error result from another error result.
347 template <typename E2
>
348 MOZ_IMPLICIT
Result(GenericErrorResult
<E2
>&& aErrorResult
)
349 : mImpl(std::forward
<E2
>(aErrorResult
.mErrorValue
)) {
350 static_assert(mozilla::IsConvertible
<E2
, E
>::value
,
351 "E2 must be convertible to E");
356 * Implementation detail of MOZ_TRY().
357 * Create an error result from another error result.
359 template <typename E2
>
360 MOZ_IMPLICIT
Result(const GenericErrorResult
<E2
>& aErrorResult
)
361 : mImpl(aErrorResult
.mErrorValue
) {
362 static_assert(mozilla::IsConvertible
<E2
, E
>::value
,
363 "E2 must be convertible to E");
367 Result(const Result
&) = default;
368 Result(Result
&&) = default;
369 Result
& operator=(const Result
&) = default;
370 Result
& operator=(Result
&&) = default;
372 /** True if this Result is a success result. */
373 bool isOk() const { return mImpl
.isOk(); }
375 /** True if this Result is an error result. */
376 bool isErr() const { return !mImpl
.isOk(); }
378 /** Take the success value from this Result, which must be a success result.
382 return mImpl
.unwrap();
386 * Take the success value from this Result, which must be a success result.
387 * If it is an error result, then return the aValue.
389 V
unwrapOr(V aValue
) {
390 return MOZ_LIKELY(isOk()) ? mImpl
.unwrap() : std::move(aValue
);
393 /** Take the error value from this Result, which must be an error result. */
396 return mImpl
.unwrapErr();
399 /** See the success value from this Result, which must be a success result. */
400 const V
& inspect() const { return mImpl
.inspect(); }
402 /** See the error value from this Result, which must be an error result. */
403 const E
& inspectErr() const {
405 return mImpl
.inspectErr();
409 * Map a function V -> W over this result's success variant. If this result is
410 * an error, do not invoke the function and return a copy of the error.
412 * Mapping over success values invokes the function to produce a new success
415 * // Map Result<int, E> to another Result<int, E>
416 * Result<int, E> res(5);
417 * Result<int, E> res2 = res.map([](int x) { return x * x; });
418 * MOZ_ASSERT(res2.unwrap() == 25);
420 * // Map Result<const char*, E> to Result<size_t, E>
421 * Result<const char*, E> res("hello, map!");
422 * Result<size_t, E> res2 = res.map(strlen);
423 * MOZ_ASSERT(res2.unwrap() == 11);
425 * Mapping over an error does not invoke the function and copies the error:
427 * Result<V, int> res(5);
428 * MOZ_ASSERT(res.isErr());
429 * Result<W, int> res2 = res.map([](V v) { ... });
430 * MOZ_ASSERT(res2.isErr());
431 * MOZ_ASSERT(res2.unwrapErr() == 5);
433 template <typename F
>
434 auto map(F f
) -> Result
<decltype(f(*((V
*)nullptr))), E
> {
435 using RetResult
= Result
<decltype(f(*((V
*)nullptr))), E
>;
436 return MOZ_LIKELY(isOk()) ? RetResult(f(unwrap())) : RetResult(unwrapErr());
440 * Map a function V -> W over this result's error variant. If this result is
441 * a success, do not invoke the function and move the success over.
443 * Mapping over error values invokes the function to produce a new error
446 * // Map Result<V, int> to another Result<V, int>
447 * Result<V, int> res(5);
448 * Result<V, int> res2 = res.mapErr([](int x) { return x * x; });
449 * MOZ_ASSERT(res2.unwrapErr() == 25);
451 * // Map Result<V, const char*> to Result<V, size_t>
452 * Result<V, const char*> res("hello, map!");
453 * Result<size_t, E> res2 = res.mapErr(strlen);
454 * MOZ_ASSERT(res2.unwrapErr() == 11);
456 * Mapping over a success does not invoke the function and copies the error:
458 * Result<int, V> res(5);
459 * MOZ_ASSERT(res.isOk());
460 * Result<int, W> res2 = res.mapErr([](V v) { ... });
461 * MOZ_ASSERT(res2.isOk());
462 * MOZ_ASSERT(res2.unwrap() == 5);
464 template <typename F
>
465 auto mapErr(F f
) -> Result
<V
, std::result_of_t
<F(E
)>> {
466 using RetResult
= Result
<V
, std::result_of_t
<F(E
)>>;
467 return isOk() ? RetResult(unwrap()) : RetResult(f(unwrapErr()));
471 * Given a function V -> Result<W, E>, apply it to this result's success value
472 * and return its result. If this result is an error value, then return a
475 * This is sometimes called "flatMap" or ">>=" in other contexts.
477 * `andThen`ing over success values invokes the function to produce a new
480 * Result<const char*, Error> res("hello, andThen!");
481 * Result<HtmlFreeString, Error> res2 = res.andThen([](const char* s) {
482 * return containsHtmlTag(s)
483 * ? Result<HtmlFreeString, Error>(Error("Invalid: contains HTML"))
484 * : Result<HtmlFreeString, Error>(HtmlFreeString(s));
487 * MOZ_ASSERT(res2.isOk());
488 * MOZ_ASSERT(res2.unwrap() == HtmlFreeString("hello, andThen!");
490 * `andThen`ing over error results does not invoke the function, and just
491 * produces a new copy of the error result:
493 * Result<int, const char*> res("some error");
494 * auto res2 = res.andThen([](int x) { ... });
495 * MOZ_ASSERT(res2.isErr());
496 * MOZ_ASSERT(res.unwrapErr() == res2.unwrapErr());
498 template <typename F
, typename
= typename EnableIf
<detail::IsResult
<decltype(
499 (*((F
*)nullptr))(*((V
*)nullptr)))>::value
>::Type
>
500 auto andThen(F f
) -> decltype(f(*((V
*)nullptr))) {
501 return MOZ_LIKELY(isOk()) ? f(unwrap())
502 : GenericErrorResult
<E
>(unwrapErr());
507 * A type that auto-converts to an error Result. This is like a Result without
508 * a success type. It's the best return type for functions that always return
509 * an error--functions designed to build and populate error objects. It's also
510 * useful in error-handling macros; see MOZ_TRY for an example.
512 template <typename E
>
513 class MOZ_MUST_USE_TYPE GenericErrorResult
{
516 template <typename V
, typename E2
>
520 explicit GenericErrorResult(E aErrorValue
)
521 : mErrorValue(std::forward
<E
>(aErrorValue
)) {}
524 template <typename E
>
525 inline GenericErrorResult
<E
> Err(E
&& aErrorValue
) {
526 return GenericErrorResult
<E
>(std::forward
<E
>(aErrorValue
));
529 } // namespace mozilla
532 * MOZ_TRY(expr) is the C++ equivalent of Rust's `try!(expr);`. First, it
533 * evaluates expr, which must produce a Result value. On success, it
534 * discards the result altogether. On error, it immediately returns an error
535 * Result from the enclosing function.
537 #define MOZ_TRY(expr) \
539 auto mozTryTempResult_ = ::mozilla::ToResult(expr); \
540 if (MOZ_UNLIKELY(mozTryTempResult_.isErr())) { \
541 return ::mozilla::Err(mozTryTempResult_.unwrapErr()); \
546 * MOZ_TRY_VAR(target, expr) is the C++ equivalent of Rust's `target =
547 * try!(expr);`. First, it evaluates expr, which must produce a Result value. On
548 * success, the result's success value is assigned to target. On error,
549 * immediately returns the error result. |target| must evaluate to a reference
550 * without any side effects.
552 #define MOZ_TRY_VAR(target, expr) \
554 auto mozTryVarTempResult_ = (expr); \
555 if (MOZ_UNLIKELY(mozTryVarTempResult_.isErr())) { \
556 return ::mozilla::Err(mozTryVarTempResult_.unwrapErr()); \
558 (target) = mozTryVarTempResult_.unwrap(); \
561 #endif // mozilla_Result_h