зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1659660 - Improve documentation and testing for mozilla::Result::map and mozilla::Result::mapErr; r=froydnj,dom-workers-and-storage-reviewers,sg
Differential Revision: https://phabricator.services.mozilla.com/D87414
This commit is contained in:
Родитель
8561a6fd69
Коммит
d749be0c59
|
@ -422,8 +422,8 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
}
|
||||
|
||||
/**
|
||||
* Map a function V -> W over this result's success variant. If this result is
|
||||
* an error, do not invoke the function and propagate the error.
|
||||
* Map a function V -> V2 over this result's success variant. If this result
|
||||
* is an error, do not invoke the function and propagate the error.
|
||||
*
|
||||
* Mapping over success values invokes the function to produce a new success
|
||||
* value:
|
||||
|
@ -431,11 +431,13 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* // Map Result<int, E> to another Result<int, E>
|
||||
* Result<int, E> res(5);
|
||||
* Result<int, E> res2 = res.map([](int x) { return x * x; });
|
||||
* MOZ_ASSERT(res.isOk());
|
||||
* MOZ_ASSERT(res2.unwrap() == 25);
|
||||
*
|
||||
* // Map Result<const char*, E> to Result<size_t, E>
|
||||
* Result<const char*, E> res("hello, map!");
|
||||
* Result<size_t, E> res2 = res.map(strlen);
|
||||
* MOZ_ASSERT(res.isOk());
|
||||
* MOZ_ASSERT(res2.unwrap() == 11);
|
||||
*
|
||||
* Mapping over an error does not invoke the function and propagates the
|
||||
|
@ -443,7 +445,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
*
|
||||
* Result<V, int> res(5);
|
||||
* MOZ_ASSERT(res.isErr());
|
||||
* Result<W, int> res2 = res.map([](V v) { ... });
|
||||
* Result<V2, int> res2 = res.map([](V v) { ... });
|
||||
* MOZ_ASSERT(res2.isErr());
|
||||
* MOZ_ASSERT(res2.unwrapErr() == 5);
|
||||
*/
|
||||
|
@ -454,7 +456,7 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
}
|
||||
|
||||
/**
|
||||
* Map a function V -> W over this result's error variant. If this result is
|
||||
* Map a function E -> E2 over this result's error variant. If this result is
|
||||
* a success, do not invoke the function and move the success over.
|
||||
*
|
||||
* Mapping over error values invokes the function to produce a new error
|
||||
|
@ -463,30 +465,34 @@ class MOZ_MUST_USE_TYPE Result final {
|
|||
* // Map Result<V, int> to another Result<V, int>
|
||||
* Result<V, int> res(5);
|
||||
* Result<V, int> res2 = res.mapErr([](int x) { return x * x; });
|
||||
* MOZ_ASSERT(res2.isErr());
|
||||
* MOZ_ASSERT(res2.unwrapErr() == 25);
|
||||
*
|
||||
* // Map Result<V, const char*> to Result<V, size_t>
|
||||
* Result<V, const char*> res("hello, map!");
|
||||
* Result<size_t, E> res2 = res.mapErr(strlen);
|
||||
* MOZ_ASSERT(res2.unwrapErr() == 11);
|
||||
* Result<V, const char*> res("hello, mapErr!");
|
||||
* Result<V, size_t> res2 = res.mapErr(strlen);
|
||||
* MOZ_ASSERT(res2.isErr());
|
||||
* MOZ_ASSERT(res2.unwrapErr() == 14);
|
||||
*
|
||||
* Mapping over a success does not invoke the function and copies the error:
|
||||
* Mapping over a success does not invoke the function and moves the success:
|
||||
*
|
||||
* Result<int, V> res(5);
|
||||
* Result<int, E> res(5);
|
||||
* MOZ_ASSERT(res.isOk());
|
||||
* Result<int, W> res2 = res.mapErr([](V v) { ... });
|
||||
* Result<int, E2> res2 = res.mapErr([](E e) { ... });
|
||||
* MOZ_ASSERT(res2.isOk());
|
||||
* MOZ_ASSERT(res2.unwrap() == 5);
|
||||
*/
|
||||
template <typename F>
|
||||
auto mapErr(F f) -> Result<V, std::result_of_t<F(E)>> {
|
||||
using RetResult = Result<V, std::result_of_t<F(E)>>;
|
||||
return isOk() ? RetResult(unwrap()) : RetResult(f(unwrapErr()));
|
||||
return MOZ_UNLIKELY(isErr()) ? RetResult(f(unwrapErr()))
|
||||
: RetResult(unwrap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a function V -> Result<W, E>, apply it to this result's success value
|
||||
* and return its result. If this result is an error value, it is propagated.
|
||||
* Given a function V -> Result<V2, E>, apply it to this result's success
|
||||
* value and return its result. If this result is an error value, it is
|
||||
* propagated.
|
||||
*
|
||||
* This is sometimes called "flatMap" or ">>=" in other contexts.
|
||||
*
|
||||
|
|
|
@ -178,34 +178,119 @@ static void MapTest() {
|
|||
explicit MyError(int y) : x(y) {}
|
||||
};
|
||||
|
||||
// Mapping over success values.
|
||||
Result<int, MyError> res(5);
|
||||
bool invoked = false;
|
||||
auto res2 = res.map([&invoked](int x) {
|
||||
MOZ_RELEASE_ASSERT(x == 5);
|
||||
invoked = true;
|
||||
return "hello";
|
||||
});
|
||||
MOZ_RELEASE_ASSERT(res2.isOk());
|
||||
MOZ_RELEASE_ASSERT(invoked);
|
||||
MOZ_RELEASE_ASSERT(strcmp(res2.unwrap(), "hello") == 0);
|
||||
// Mapping over success values, to the same success type.
|
||||
{
|
||||
Result<int, MyError> res(5);
|
||||
bool invoked = false;
|
||||
auto res2 = res.map([&invoked](int x) {
|
||||
MOZ_RELEASE_ASSERT(x == 5);
|
||||
invoked = true;
|
||||
return 6;
|
||||
});
|
||||
MOZ_RELEASE_ASSERT(res2.isOk());
|
||||
MOZ_RELEASE_ASSERT(invoked);
|
||||
MOZ_RELEASE_ASSERT(res2.unwrap() == 6);
|
||||
}
|
||||
|
||||
// Mapping over success values, to a different success type.
|
||||
{
|
||||
Result<int, MyError> res(5);
|
||||
bool invoked = false;
|
||||
auto res2 = res.map([&invoked](int x) {
|
||||
MOZ_RELEASE_ASSERT(x == 5);
|
||||
invoked = true;
|
||||
return "hello";
|
||||
});
|
||||
MOZ_RELEASE_ASSERT(res2.isOk());
|
||||
MOZ_RELEASE_ASSERT(invoked);
|
||||
MOZ_RELEASE_ASSERT(strcmp(res2.unwrap(), "hello") == 0);
|
||||
}
|
||||
|
||||
// Mapping over error values.
|
||||
MyError err(1);
|
||||
Result<char, MyError> res3(err);
|
||||
MOZ_RELEASE_ASSERT(res3.isErr());
|
||||
Result<char, MyError> res4 = res3.map([](int x) {
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
return 'a';
|
||||
});
|
||||
MOZ_RELEASE_ASSERT(res4.isErr());
|
||||
MOZ_RELEASE_ASSERT(res4.unwrapErr().x == err.x);
|
||||
{
|
||||
MyError err(1);
|
||||
Result<char, MyError> res(err);
|
||||
MOZ_RELEASE_ASSERT(res.isErr());
|
||||
Result<char, MyError> res2 = res.map([](int x) {
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
return 'a';
|
||||
});
|
||||
MOZ_RELEASE_ASSERT(res2.isErr());
|
||||
MOZ_RELEASE_ASSERT(res2.unwrapErr().x == err.x);
|
||||
}
|
||||
|
||||
// Function pointers instead of lamdbas as the mapping function.
|
||||
Result<const char*, MyError> res5("hello");
|
||||
auto res6 = res5.map(strlen);
|
||||
MOZ_RELEASE_ASSERT(res6.isOk());
|
||||
MOZ_RELEASE_ASSERT(res6.unwrap() == 5);
|
||||
// Function pointers instead of lambdas as the mapping function.
|
||||
{
|
||||
Result<const char*, MyError> res("hello");
|
||||
auto res2 = res.map(strlen);
|
||||
MOZ_RELEASE_ASSERT(res2.isOk());
|
||||
MOZ_RELEASE_ASSERT(res2.unwrap() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
static void MapErrTest() {
|
||||
struct MyError {
|
||||
int x;
|
||||
|
||||
explicit MyError(int y) : x(y) {}
|
||||
};
|
||||
|
||||
struct MyError2 {
|
||||
int a;
|
||||
|
||||
explicit MyError2(int b) : a(b) {}
|
||||
};
|
||||
|
||||
// Mapping over error values, to the same error type.
|
||||
{
|
||||
MyError err(1);
|
||||
Result<char, MyError> res(err);
|
||||
MOZ_RELEASE_ASSERT(res.isErr());
|
||||
bool invoked = false;
|
||||
auto res2 = res.mapErr([&invoked](const auto err) {
|
||||
MOZ_RELEASE_ASSERT(err.x == 1);
|
||||
invoked = true;
|
||||
return MyError(2);
|
||||
});
|
||||
MOZ_RELEASE_ASSERT(res2.isErr());
|
||||
MOZ_RELEASE_ASSERT(invoked);
|
||||
MOZ_RELEASE_ASSERT(res2.unwrapErr().x == 2);
|
||||
}
|
||||
|
||||
// Mapping over error values, to a different error type.
|
||||
{
|
||||
MyError err(1);
|
||||
Result<char, MyError> res(err);
|
||||
MOZ_RELEASE_ASSERT(res.isErr());
|
||||
bool invoked = false;
|
||||
auto res2 = res.mapErr([&invoked](const auto err) {
|
||||
MOZ_RELEASE_ASSERT(err.x == 1);
|
||||
invoked = true;
|
||||
return MyError2(2);
|
||||
});
|
||||
MOZ_RELEASE_ASSERT(res2.isErr());
|
||||
MOZ_RELEASE_ASSERT(invoked);
|
||||
MOZ_RELEASE_ASSERT(res2.unwrapErr().a == 2);
|
||||
}
|
||||
|
||||
// Mapping over success values.
|
||||
{
|
||||
Result<int, MyError> res(5);
|
||||
auto res2 = res.mapErr([](const auto err) {
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
return MyError(1);
|
||||
});
|
||||
MOZ_RELEASE_ASSERT(res2.isOk());
|
||||
MOZ_RELEASE_ASSERT(res2.unwrap() == 5);
|
||||
}
|
||||
|
||||
// Function pointers instead of lambdas as the mapping function.
|
||||
{
|
||||
Result<Ok, const char*> res("hello");
|
||||
auto res2 = res.mapErr(strlen);
|
||||
MOZ_RELEASE_ASSERT(res2.isErr());
|
||||
MOZ_RELEASE_ASSERT(res2.unwrapErr() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
static void AndThenTest() {
|
||||
|
@ -298,6 +383,7 @@ int main() {
|
|||
EmptyValueTest();
|
||||
ReferenceTest();
|
||||
MapTest();
|
||||
MapErrTest();
|
||||
AndThenTest();
|
||||
UniquePtrTest();
|
||||
return 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче