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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "mozilla/ResultVariant.h"
10 #include "mozilla/Try.h"
11 #include "mozilla/UniquePtr.h"
14 using mozilla::GenericErrorResult
;
16 using mozilla::Result
;
17 using mozilla::UniquePtr
;
19 #define MOZ_STATIC_AND_RELEASE_ASSERT(expr) \
20 static_assert(expr); \
21 MOZ_RELEASE_ASSERT(expr)
23 enum struct TestUnusedZeroEnum
: int16_t { Ok
= 0, NotOk
= 1 };
25 namespace mozilla::detail
{
27 struct UnusedZero
<TestUnusedZeroEnum
> : UnusedZeroEnum
<TestUnusedZeroEnum
> {};
28 } // namespace mozilla::detail
32 namespace mozilla::detail
{
34 struct UnusedZero
<Failed
> {
35 using StorageType
= uintptr_t;
37 static constexpr bool value
= true;
38 static constexpr StorageType nullValue
= 0;
39 static constexpr StorageType
GetDefaultValue() { return 2; }
41 static constexpr void AssertValid(StorageType aValue
) {}
42 static constexpr Failed
Inspect(const StorageType
& aValue
) {
45 static constexpr Failed
Unwrap(StorageType aValue
) { return Failed
{}; }
46 static constexpr StorageType
Store(Failed aValue
) {
47 return GetDefaultValue();
51 } // namespace mozilla::detail
53 // V is trivially default-constructible, and E has UnusedZero<E>::value == true,
54 // for a reference type and for a non-reference type
55 static_assert(mozilla::detail::SelectResultImpl
<uintptr_t, Failed
>::value
==
56 mozilla::detail::PackingStrategy::NullIsOk
);
58 mozilla::detail::SelectResultImpl
<Ok
, TestUnusedZeroEnum
>::value
==
59 mozilla::detail::PackingStrategy::NullIsOk
);
60 static_assert(mozilla::detail::SelectResultImpl
<Ok
, Failed
>::value
==
61 mozilla::detail::PackingStrategy::LowBitTagIsError
);
63 static_assert(std::is_trivially_destructible_v
<Result
<uintptr_t, Failed
>>);
64 static_assert(std::is_trivially_destructible_v
<Result
<Ok
, TestUnusedZeroEnum
>>);
65 static_assert(std::is_trivially_destructible_v
<Result
<Ok
, Failed
>>);
68 sizeof(Result
<bool, TestUnusedZeroEnum
>) <= sizeof(uintptr_t),
69 "Result with bool value type should not be larger than pointer-sized");
70 static_assert(sizeof(Result
<Ok
, Failed
>) == sizeof(uint8_t),
71 "Result with empty value type should be size 1");
72 static_assert(sizeof(Result
<int*, Failed
>) == sizeof(uintptr_t),
73 "Result with two aligned pointer types should be pointer-sized");
75 sizeof(Result
<char*, Failed
*>) > sizeof(char*),
76 "Result with unaligned success type `char*` must not be pointer-sized");
78 sizeof(Result
<int*, char*>) > sizeof(char*),
79 "Result with unaligned error type `char*` must not be pointer-sized");
81 enum Foo8
: uint8_t {};
82 enum Foo16
: uint16_t {};
83 enum Foo32
: uint32_t {};
84 static_assert(sizeof(Result
<Ok
, Foo8
>) <= sizeof(uintptr_t),
85 "Result with small types should be pointer-sized");
86 static_assert(sizeof(Result
<Ok
, Foo16
>) <= sizeof(uintptr_t),
87 "Result with small types should be pointer-sized");
88 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
89 sizeof(Result
<Ok
, Foo32
>) <= sizeof(uintptr_t),
90 "Result with small types should be pointer-sized");
92 static_assert(sizeof(Result
<Foo16
, Foo8
>) <= sizeof(uintptr_t),
93 "Result with small types should be pointer-sized");
94 static_assert(sizeof(Result
<Foo8
, Foo16
>) <= sizeof(uintptr_t),
95 "Result with small types should be pointer-sized");
96 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
97 sizeof(Result
<Foo32
, Foo16
>) <= sizeof(uintptr_t),
98 "Result with small types should be pointer-sized");
99 static_assert(sizeof(Foo32
) >= sizeof(uintptr_t) ||
100 sizeof(Result
<Foo16
, Foo32
>) <= sizeof(uintptr_t),
101 "Result with small types should be pointer-sized");
103 #if __cplusplus < 202002L
104 static_assert(std::is_literal_type_v
<Result
<int*, Failed
>>);
105 static_assert(std::is_literal_type_v
<Result
<Ok
, Failed
>>);
106 static_assert(std::is_literal_type_v
<Result
<Ok
, Foo8
>>);
107 static_assert(std::is_literal_type_v
<Result
<Foo8
, Foo16
>>);
108 static_assert(!std::is_literal_type_v
<Result
<Ok
, UniquePtr
<int>>>);
111 static constexpr GenericErrorResult
<Failed
> Fail() { return Err(Failed
{}); }
113 static constexpr GenericErrorResult
<TestUnusedZeroEnum
>
114 FailTestUnusedZeroEnum() {
115 return Err(TestUnusedZeroEnum::NotOk
);
118 static constexpr Result
<Ok
, Failed
> Task1(bool pass
) {
120 return Fail(); // implicit conversion from GenericErrorResult to Result
125 static constexpr Result
<Ok
, TestUnusedZeroEnum
> Task1UnusedZeroEnumErr(
128 return FailTestUnusedZeroEnum(); // implicit conversion from
129 // GenericErrorResult to Result
134 static constexpr Result
<int, Failed
> Task2(bool pass
, int value
) {
136 Task1(pass
)); // converts one type of result to another in the error case
137 return value
; // implicit conversion from T to Result<T, E>
140 static constexpr Result
<int, TestUnusedZeroEnum
> Task2UnusedZeroEnumErr(
141 bool pass
, int value
) {
142 MOZ_TRY(Task1UnusedZeroEnumErr(
143 pass
)); // converts one type of result to another in the error case
144 return value
; // implicit conversion from T to Result<T, E>
147 static Result
<int, Failed
> Task3(bool pass1
, bool pass2
, int value
) {
149 MOZ_TRY_VAR(x
, Task2(pass1
, value
));
150 MOZ_TRY_VAR(y
, Task2(pass2
, value
));
154 static void BasicTests() {
155 MOZ_STATIC_AND_RELEASE_ASSERT(Task1(true).isOk());
156 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1(true).isErr());
157 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1(false).isOk());
158 MOZ_STATIC_AND_RELEASE_ASSERT(Task1(false).isErr());
160 MOZ_STATIC_AND_RELEASE_ASSERT(Task1UnusedZeroEnumErr(true).isOk());
161 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(true).isErr());
162 MOZ_STATIC_AND_RELEASE_ASSERT(!Task1UnusedZeroEnumErr(false).isOk());
163 MOZ_STATIC_AND_RELEASE_ASSERT(Task1UnusedZeroEnumErr(false).isErr());
164 MOZ_STATIC_AND_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk
==
165 Task1UnusedZeroEnumErr(false).inspectErr());
166 MOZ_STATIC_AND_RELEASE_ASSERT(TestUnusedZeroEnum::NotOk
==
167 Task1UnusedZeroEnumErr(false).unwrapErr());
170 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).isOk());
171 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).unwrap() == 3);
172 MOZ_STATIC_AND_RELEASE_ASSERT(Task2(true, 3).unwrapOr(6) == 3);
173 MOZ_RELEASE_ASSERT(Task2(false, 3).isErr());
174 MOZ_RELEASE_ASSERT(Task2(false, 3).unwrapOr(6) == 6);
176 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).isOk());
177 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrap() == 3);
178 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(true, 3).unwrapOr(6) ==
180 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).isErr());
181 MOZ_STATIC_AND_RELEASE_ASSERT(Task2UnusedZeroEnumErr(false, 3).unwrapOr(6) ==
184 // MOZ_TRY_VAR works.
185 MOZ_RELEASE_ASSERT(Task3(true, true, 3).isOk());
186 MOZ_RELEASE_ASSERT(Task3(true, true, 3).unwrap() == 6);
187 MOZ_RELEASE_ASSERT(Task3(true, false, 3).isErr());
188 MOZ_RELEASE_ASSERT(Task3(false, true, 3).isErr());
189 MOZ_RELEASE_ASSERT(Task3(false, true, 3).unwrapOr(6) == 6);
191 // Lvalues should work too.
193 constexpr Result
<Ok
, Failed
> res1
= Task1(true);
194 MOZ_STATIC_AND_RELEASE_ASSERT(res1
.isOk());
195 MOZ_STATIC_AND_RELEASE_ASSERT(!res1
.isErr());
197 constexpr Result
<Ok
, Failed
> res2
= Task1(false);
198 MOZ_STATIC_AND_RELEASE_ASSERT(!res2
.isOk());
199 MOZ_STATIC_AND_RELEASE_ASSERT(res2
.isErr());
203 Result
<int, Failed
> res
= Task2(true, 3);
204 MOZ_RELEASE_ASSERT(res
.isOk());
205 MOZ_RELEASE_ASSERT(res
.unwrap() == 3);
207 res
= Task2(false, 4);
208 MOZ_RELEASE_ASSERT(res
.isErr());
211 // Some tests for pointer tagging.
215 Result
<int*, Failed
> res
= &i
;
216 static_assert(sizeof(res
) == sizeof(uintptr_t),
217 "should use pointer tagging to fit in a word");
219 MOZ_RELEASE_ASSERT(res
.isOk());
220 MOZ_RELEASE_ASSERT(*res
.unwrap() == 123);
223 MOZ_RELEASE_ASSERT(res
.isErr());
227 struct NonCopyableNonMovable
{
228 explicit constexpr NonCopyableNonMovable(uint32_t aValue
) : mValue(aValue
) {}
230 NonCopyableNonMovable(const NonCopyableNonMovable
&) = delete;
231 NonCopyableNonMovable(NonCopyableNonMovable
&&) = delete;
232 NonCopyableNonMovable
& operator=(const NonCopyableNonMovable
&) = delete;
233 NonCopyableNonMovable
& operator=(NonCopyableNonMovable
&&) = delete;
238 static void InPlaceConstructionTests() {
240 // PackingStrategy == NullIsOk
241 static_assert(mozilla::detail::SelectResultImpl
<NonCopyableNonMovable
,
243 mozilla::detail::PackingStrategy::NullIsOk
);
244 constexpr Result
<NonCopyableNonMovable
, Failed
> result
{std::in_place
, 42u};
245 MOZ_STATIC_AND_RELEASE_ASSERT(42 == result
.inspect().mValue
);
249 // PackingStrategy == Variant
251 mozilla::detail::SelectResultImpl
<NonCopyableNonMovable
, int>::value
==
252 mozilla::detail::PackingStrategy::Variant
);
253 const Result
<NonCopyableNonMovable
, int> result
{std::in_place
, 42};
254 MOZ_RELEASE_ASSERT(42 == result
.inspect().mValue
);
260 struct Snafu
: Failed
{};
262 static Result
<Ok
, Snafu
*> Explode() {
267 static Result
<Ok
, Failed
*> ErrorGeneralization() {
268 MOZ_TRY(Explode()); // change error type from Snafu* to more general Failed*
272 static void TypeConversionTests() {
273 MOZ_RELEASE_ASSERT(ErrorGeneralization().isErr());
276 const Result
<Ok
, Failed
*> res
= Explode();
277 MOZ_RELEASE_ASSERT(res
.isErr());
281 const Result
<Ok
, Failed
*> res
= Result
<Ok
, Snafu
*>{Ok
{}};
282 MOZ_RELEASE_ASSERT(res
.isOk());
286 static void EmptyValueTest() {
288 mozilla::Result
<Fine
, Failed
> res((Fine()));
290 MOZ_RELEASE_ASSERT(res
.isOk());
291 static_assert(sizeof(res
) == sizeof(uint8_t),
292 "Result with empty value and error types should be size 1");
295 static void MapTest() {
299 explicit MyError(int y
) : x(y
) {}
302 // Mapping over success values, to the same success type.
304 Result
<int, MyError
> res(5);
305 bool invoked
= false;
306 auto res2
= res
.map([&invoked
](int x
) {
307 MOZ_RELEASE_ASSERT(x
== 5);
311 MOZ_RELEASE_ASSERT(res2
.isOk());
312 MOZ_RELEASE_ASSERT(invoked
);
313 MOZ_RELEASE_ASSERT(res2
.unwrap() == 6);
316 // Mapping over success values, to a different success type.
318 Result
<int, MyError
> res(5);
319 bool invoked
= false;
320 auto res2
= res
.map([&invoked
](int x
) {
321 MOZ_RELEASE_ASSERT(x
== 5);
325 MOZ_RELEASE_ASSERT(res2
.isOk());
326 MOZ_RELEASE_ASSERT(invoked
);
327 MOZ_RELEASE_ASSERT(strcmp(res2
.unwrap(), "hello") == 0);
330 // Mapping over success values (constexpr).
332 constexpr uint64_t kValue
= 42u;
333 constexpr auto res2a
= Result
<int32_t, Failed
>{5}.map([](int32_t x
) {
334 MOZ_RELEASE_ASSERT(x
== 5);
337 MOZ_STATIC_AND_RELEASE_ASSERT(res2a
.isOk());
338 MOZ_STATIC_AND_RELEASE_ASSERT(kValue
== res2a
.inspect());
341 // Mapping over error values.
344 Result
<char, MyError
> res(err
);
345 MOZ_RELEASE_ASSERT(res
.isErr());
346 Result
<char, MyError
> res2
= res
.map([](int x
) {
347 MOZ_RELEASE_ASSERT(false);
350 MOZ_RELEASE_ASSERT(res2
.isErr());
351 MOZ_RELEASE_ASSERT(res2
.unwrapErr().x
== err
.x
);
354 // Function pointers instead of lambdas as the mapping function.
356 Result
<const char*, MyError
> res("hello");
357 auto res2
= res
.map(strlen
);
358 MOZ_RELEASE_ASSERT(res2
.isOk());
359 MOZ_RELEASE_ASSERT(res2
.unwrap() == 5);
363 static void MapErrTest() {
367 explicit MyError(int y
) : x(y
) {}
373 explicit MyError2(int b
) : a(b
) {}
376 // Mapping over error values, to the same error type.
379 Result
<char, MyError
> res(err
);
380 MOZ_RELEASE_ASSERT(res
.isErr());
381 bool invoked
= false;
382 auto res2
= res
.mapErr([&invoked
](const auto err
) {
383 MOZ_RELEASE_ASSERT(err
.x
== 1);
387 MOZ_RELEASE_ASSERT(res2
.isErr());
388 MOZ_RELEASE_ASSERT(invoked
);
389 MOZ_RELEASE_ASSERT(res2
.unwrapErr().x
== 2);
392 // Mapping over error values, to a different error type.
395 Result
<char, MyError
> res(err
);
396 MOZ_RELEASE_ASSERT(res
.isErr());
397 bool invoked
= false;
398 auto res2
= res
.mapErr([&invoked
](const auto err
) {
399 MOZ_RELEASE_ASSERT(err
.x
== 1);
403 MOZ_RELEASE_ASSERT(res2
.isErr());
404 MOZ_RELEASE_ASSERT(invoked
);
405 MOZ_RELEASE_ASSERT(res2
.unwrapErr().a
== 2);
408 // Mapping over success values.
410 Result
<int, MyError
> res(5);
411 auto res2
= res
.mapErr([](const auto err
) {
412 MOZ_RELEASE_ASSERT(false);
415 MOZ_RELEASE_ASSERT(res2
.isOk());
416 MOZ_RELEASE_ASSERT(res2
.unwrap() == 5);
419 // Function pointers instead of lambdas as the mapping function.
421 Result
<Ok
, const char*> res("hello");
422 auto res2
= res
.mapErr(strlen
);
423 MOZ_RELEASE_ASSERT(res2
.isErr());
424 MOZ_RELEASE_ASSERT(res2
.unwrapErr() == 5);
428 static Result
<Ok
, size_t> strlen_ResultWrapper(const char* aValue
) {
429 return Err(strlen(aValue
));
432 static void OrElseTest() {
436 explicit constexpr MyError(int y
) : x(y
) {}
442 explicit constexpr MyError2(int b
) : a(b
) {}
445 // `orElse`ing over error values, to Result<V, E> (the same error type) error
449 Result
<char, MyError
> res(err
);
450 MOZ_RELEASE_ASSERT(res
.isErr());
451 bool invoked
= false;
452 auto res2
= res
.orElse([&invoked
](const auto err
) -> Result
<char, MyError
> {
453 MOZ_RELEASE_ASSERT(err
.x
== 1);
456 return Err(MyError(2));
460 MOZ_RELEASE_ASSERT(res2
.isErr());
461 MOZ_RELEASE_ASSERT(invoked
);
462 MOZ_RELEASE_ASSERT(res2
.unwrapErr().x
== 2);
465 // `orElse`ing over error values, to Result<V, E> (the same error type)
469 Result
<char, MyError
> res(err
);
470 MOZ_RELEASE_ASSERT(res
.isErr());
471 bool invoked
= false;
472 auto res2
= res
.orElse([&invoked
](const auto err
) -> Result
<char, MyError
> {
473 MOZ_RELEASE_ASSERT(err
.x
== 42);
476 return Err(MyError(2));
480 MOZ_RELEASE_ASSERT(res2
.isOk());
481 MOZ_RELEASE_ASSERT(invoked
);
482 MOZ_RELEASE_ASSERT(res2
.unwrap() == 'a');
485 // `orElse`ing over error values, to Result<V, E2> (a different error type)
489 Result
<char, MyError
> res(err
);
490 MOZ_RELEASE_ASSERT(res
.isErr());
491 bool invoked
= false;
493 res
.orElse([&invoked
](const auto err
) -> Result
<char, MyError2
> {
494 MOZ_RELEASE_ASSERT(err
.x
== 1);
497 return Err(MyError2(2));
501 MOZ_RELEASE_ASSERT(res2
.isErr());
502 MOZ_RELEASE_ASSERT(invoked
);
503 MOZ_RELEASE_ASSERT(res2
.unwrapErr().a
== 2);
506 // `orElse`ing over error values, to Result<V, E2> (a different error type)
510 Result
<char, MyError
> res(err
);
511 MOZ_RELEASE_ASSERT(res
.isErr());
512 bool invoked
= false;
514 res
.orElse([&invoked
](const auto err
) -> Result
<char, MyError2
> {
515 MOZ_RELEASE_ASSERT(err
.x
== 42);
518 return Err(MyError2(2));
522 MOZ_RELEASE_ASSERT(res2
.isOk());
523 MOZ_RELEASE_ASSERT(invoked
);
524 MOZ_RELEASE_ASSERT(res2
.unwrap() == 'a');
527 // `orElse`ing over success values.
529 Result
<int, MyError
> res(5);
530 auto res2
= res
.orElse([](const auto err
) -> Result
<int, MyError
> {
531 MOZ_RELEASE_ASSERT(false);
532 return Err(MyError(1));
534 MOZ_RELEASE_ASSERT(res2
.isOk());
535 MOZ_RELEASE_ASSERT(res2
.unwrap() == 5);
538 // Function pointers instead of lambdas as the `orElse`ing function.
540 Result
<Ok
, const char*> res("hello");
541 auto res2
= res
.orElse(strlen_ResultWrapper
);
542 MOZ_RELEASE_ASSERT(res2
.isErr());
543 MOZ_RELEASE_ASSERT(res2
.unwrapErr() == 5);
547 static void AndThenTest() {
548 // `andThen`ing over success results.
550 Result
<int, const char*> r1(10);
551 Result
<int, const char*> r2
=
552 r1
.andThen([](int x
) { return Result
<int, const char*>(x
+ 1); });
553 MOZ_RELEASE_ASSERT(r2
.isOk());
554 MOZ_RELEASE_ASSERT(r2
.unwrap() == 11);
557 // `andThen`ing over success results (constexpr).
559 constexpr Result
<int, Failed
> r2a
= Result
<int, Failed
>{10}.andThen(
560 [](int x
) { return Result
<int, Failed
>(x
+ 1); });
561 MOZ_STATIC_AND_RELEASE_ASSERT(r2a
.isOk());
562 MOZ_STATIC_AND_RELEASE_ASSERT(r2a
.inspect() == 11);
565 // `andThen`ing over error results.
567 Result
<int, const char*> r3("error");
568 Result
<int, const char*> r4
= r3
.andThen([](int x
) {
569 MOZ_RELEASE_ASSERT(false);
570 return Result
<int, const char*>(1);
572 MOZ_RELEASE_ASSERT(r4
.isErr());
573 MOZ_RELEASE_ASSERT(r3
.unwrapErr() == r4
.unwrapErr());
576 // andThen with a function accepting an rvalue
578 Result
<int, const char*> r1(10);
579 Result
<int, const char*> r2
=
580 r1
.andThen([](int&& x
) { return Result
<int, const char*>(x
+ 1); });
581 MOZ_RELEASE_ASSERT(r2
.isOk());
582 MOZ_RELEASE_ASSERT(r2
.unwrap() == 11);
585 // `andThen`ing over error results (constexpr).
587 constexpr Result
<int, Failed
> r4a
=
588 Result
<int, Failed
>{Failed
{}}.andThen([](int x
) {
589 MOZ_RELEASE_ASSERT(false);
590 return Result
<int, Failed
>(1);
592 MOZ_STATIC_AND_RELEASE_ASSERT(r4a
.isErr());
596 using UniqueResult
= Result
<UniquePtr
<int>, const char*>;
598 static UniqueResult
UniqueTask() { return mozilla::MakeUnique
<int>(3); }
599 static UniqueResult
UniqueTaskError() { return Err("bad"); }
601 using UniqueErrorResult
= Result
<int, UniquePtr
<int>>;
602 static UniqueErrorResult
UniqueError() {
603 return Err(mozilla::MakeUnique
<int>(4));
606 static Result
<Ok
, UniquePtr
<int>> TryUniqueErrorResult() {
607 MOZ_TRY(UniqueError());
611 static void UniquePtrTest() {
613 auto result
= UniqueTask();
614 MOZ_RELEASE_ASSERT(result
.isOk());
615 auto ptr
= result
.unwrap();
616 MOZ_RELEASE_ASSERT(ptr
);
617 MOZ_RELEASE_ASSERT(*ptr
== 3);
618 auto moved
= result
.unwrap();
619 MOZ_RELEASE_ASSERT(!moved
);
623 auto err
= UniqueTaskError();
624 MOZ_RELEASE_ASSERT(err
.isErr());
625 auto ptr
= err
.unwrapOr(mozilla::MakeUnique
<int>(4));
626 MOZ_RELEASE_ASSERT(ptr
);
627 MOZ_RELEASE_ASSERT(*ptr
== 4);
631 auto result
= UniqueTaskError();
632 result
= UniqueResult(mozilla::MakeUnique
<int>(6));
633 MOZ_RELEASE_ASSERT(result
.isOk());
634 MOZ_RELEASE_ASSERT(result
.inspect() && *result
.inspect() == 6);
638 auto result
= UniqueError();
639 MOZ_RELEASE_ASSERT(result
.isErr());
640 MOZ_RELEASE_ASSERT(result
.inspectErr());
641 MOZ_RELEASE_ASSERT(*result
.inspectErr() == 4);
642 auto err
= result
.unwrapErr();
643 MOZ_RELEASE_ASSERT(!result
.inspectErr());
644 MOZ_RELEASE_ASSERT(err
);
645 MOZ_RELEASE_ASSERT(*err
== 4);
647 result
= UniqueErrorResult(0);
648 MOZ_RELEASE_ASSERT(result
.isOk() && result
.unwrap() == 0);
652 auto result
= TryUniqueErrorResult();
653 MOZ_RELEASE_ASSERT(result
.isErr());
654 auto err
= result
.unwrapErr();
655 MOZ_RELEASE_ASSERT(err
&& *err
== 4);
656 MOZ_RELEASE_ASSERT(!result
.inspectErr());
660 struct ZeroIsUnusedStructForPointer
{
663 enum class ZeroIsUnusedEnum1
: uint8_t {
667 enum class ZeroIsUnusedEnum2
: uint16_t {
671 enum class ZeroIsUnusedEnum4
: uint32_t {
675 enum class ZeroIsUnusedEnum8
: uint64_t {
679 struct EmptyErrorStruct
{};
682 struct mozilla::detail::UnusedZero
<ZeroIsUnusedStructForPointer
*> {
683 static const bool value
= true;
686 struct mozilla::detail::UnusedZero
<ZeroIsUnusedEnum1
> {
687 static const bool value
= true;
690 struct mozilla::detail::UnusedZero
<ZeroIsUnusedEnum2
> {
691 static const bool value
= true;
694 struct mozilla::detail::UnusedZero
<ZeroIsUnusedEnum4
> {
695 static const bool value
= true;
698 struct mozilla::detail::UnusedZero
<ZeroIsUnusedEnum8
> {
699 static const bool value
= true;
702 static void ZeroIsEmptyErrorTest() {
704 ZeroIsUnusedStructForPointer s
;
706 using V
= ZeroIsUnusedStructForPointer
*;
708 mozilla::Result
<V
, EmptyErrorStruct
> result(&s
);
709 MOZ_RELEASE_ASSERT(sizeof(result
) == sizeof(V
));
711 MOZ_RELEASE_ASSERT(result
.isOk());
712 MOZ_RELEASE_ASSERT(result
.inspect() == &s
);
716 using V
= ZeroIsUnusedStructForPointer
*;
718 mozilla::Result
<V
, EmptyErrorStruct
> result(Err(EmptyErrorStruct
{}));
720 MOZ_RELEASE_ASSERT(result
.isErr());
721 MOZ_RELEASE_ASSERT(*reinterpret_cast<V
*>(&result
) == nullptr);
725 ZeroIsUnusedEnum1 e
= ZeroIsUnusedEnum1::V1
;
727 using V
= ZeroIsUnusedEnum1
;
729 mozilla::Result
<V
, EmptyErrorStruct
> result(e
);
730 MOZ_RELEASE_ASSERT(sizeof(result
) == sizeof(V
));
732 MOZ_RELEASE_ASSERT(result
.isOk());
733 MOZ_RELEASE_ASSERT(result
.inspect() == e
);
737 using V
= ZeroIsUnusedEnum1
;
739 mozilla::Result
<V
, EmptyErrorStruct
> result(Err(EmptyErrorStruct()));
741 MOZ_RELEASE_ASSERT(result
.isErr());
742 MOZ_RELEASE_ASSERT(*reinterpret_cast<uint8_t*>(&result
) == 0);
746 ZeroIsUnusedEnum2 e
= ZeroIsUnusedEnum2::V1
;
748 using V
= ZeroIsUnusedEnum2
;
750 mozilla::Result
<V
, EmptyErrorStruct
> result(e
);
751 MOZ_RELEASE_ASSERT(sizeof(result
) == sizeof(V
));
753 MOZ_RELEASE_ASSERT(result
.isOk());
754 MOZ_RELEASE_ASSERT(result
.inspect() == e
);
758 using V
= ZeroIsUnusedEnum2
;
760 mozilla::Result
<V
, EmptyErrorStruct
> result(Err(EmptyErrorStruct()));
762 MOZ_RELEASE_ASSERT(result
.isErr());
763 MOZ_RELEASE_ASSERT(*reinterpret_cast<uint16_t*>(&result
) == 0);
767 ZeroIsUnusedEnum4 e
= ZeroIsUnusedEnum4::V1
;
769 using V
= ZeroIsUnusedEnum4
;
771 mozilla::Result
<V
, EmptyErrorStruct
> result(e
);
772 MOZ_RELEASE_ASSERT(sizeof(result
) == sizeof(V
));
774 MOZ_RELEASE_ASSERT(result
.isOk());
775 MOZ_RELEASE_ASSERT(result
.inspect() == e
);
779 using V
= ZeroIsUnusedEnum4
;
781 mozilla::Result
<V
, EmptyErrorStruct
> result(Err(EmptyErrorStruct()));
783 MOZ_RELEASE_ASSERT(result
.isErr());
784 MOZ_RELEASE_ASSERT(*reinterpret_cast<uint32_t*>(&result
) == 0);
788 ZeroIsUnusedEnum8 e
= ZeroIsUnusedEnum8::V1
;
790 using V
= ZeroIsUnusedEnum8
;
792 mozilla::Result
<V
, EmptyErrorStruct
> result(e
);
793 MOZ_RELEASE_ASSERT(sizeof(result
) == sizeof(V
));
795 MOZ_RELEASE_ASSERT(result
.isOk());
796 MOZ_RELEASE_ASSERT(result
.inspect() == e
);
800 using V
= ZeroIsUnusedEnum8
;
802 mozilla::Result
<V
, EmptyErrorStruct
> result(Err(EmptyErrorStruct()));
804 MOZ_RELEASE_ASSERT(result
.isErr());
805 MOZ_RELEASE_ASSERT(*reinterpret_cast<uint64_t*>(&result
) == 0);
812 class C2
: public C1
{};
815 class E2
: public E1
{};
821 mozilla::Result
<C2
*, Failed
> result(&c2
);
822 mozilla::Result
<C1
*, Failed
> copied(std::move(result
));
824 MOZ_RELEASE_ASSERT(copied
.inspect() == &c2
);
830 mozilla::Result
<Foo
, E2
*> result(Err(&e2
));
831 mozilla::Result
<Foo
, E1
*> copied(std::move(result
));
833 MOZ_RELEASE_ASSERT(copied
.inspectErr() == &e2
);
839 mozilla::Result
<C2
*, E2
*> result(&c2
);
840 mozilla::Result
<C1
*, E1
*> copied(std::move(result
));
842 MOZ_RELEASE_ASSERT(copied
.inspect() == &c2
);
848 mozilla::Result
<C2
*, E2
*> result(Err(&e2
));
849 mozilla::Result
<C1
*, E1
*> copied(std::move(result
));
851 MOZ_RELEASE_ASSERT(copied
.inspectErr() == &e2
);
859 InPlaceConstructionTests();
860 TypeConversionTests();
867 ZeroIsEmptyErrorTest();