Bug 1324829 - Add the mozilla::Result::andThen method; r=froydnj

This commit is contained in:
Nick Fitzgerald 2016-12-21 13:05:56 -08:00
parent f40c749727
commit a19333ea56
2 changed files with 67 additions and 0 deletions

View File

@ -26,6 +26,7 @@ namespace mozilla {
struct Ok {};
template <typename E> class GenericErrorResult;
template <typename V, typename E> class Result;
namespace detail {
@ -134,6 +135,12 @@ template <typename T> struct HasFreeLSB<T&> {
static const bool value = HasFreeLSB<T*>::value;
};
template <typename T>
struct IsResult : FalseType { };
template <typename V, typename E>
struct IsResult<Result<V, E>> : TrueType { };
} // namespace detail
/**
@ -251,6 +258,44 @@ public:
using RetResult = Result<decltype(f(*((V*) nullptr))), E>;
return isOk() ? RetResult(f(unwrap())) : RetResult(unwrapErr());
}
/**
* 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, then return a
* copy.
*
* This is sometimes called "flatMap" or ">>=" in other contexts.
*
* `andThen`ing over success values invokes the function to produce a new
* result:
*
* Result<const char*, Error> res("hello, andThen!");
* Result<HtmlFreeString, Error> res2 = res.andThen([](const char* s) {
* return containsHtmlTag(s)
* ? Result<HtmlFreeString, Error>(Error("Invalid: contains HTML"))
* : Result<HtmlFreeString, Error>(HtmlFreeString(s));
* }
* });
* MOZ_ASSERT(res2.isOk());
* MOZ_ASSERT(res2.unwrap() == HtmlFreeString("hello, andThen!");
*
* `andThen`ing over error results does not invoke the function, and just
* produces a new copy of the error result:
*
* Result<int, const char*> res("some error");
* auto res2 = res.andThen([](int x) { ... });
* MOZ_ASSERT(res2.isErr());
* MOZ_ASSERT(res.unwrapErr() == res2.unwrapErr());
*/
template<
typename F,
typename = typename EnableIf<
detail::IsResult<decltype((*((F*) nullptr))(*((V*) nullptr)))>::value
>::Type
>
auto andThen(F f) const -> decltype(f(*((V*) nullptr))) {
return isOk() ? f(unwrap()) : GenericErrorResult<E>(unwrapErr());
}
};
/**

View File

@ -200,6 +200,27 @@ MapTest()
MOZ_RELEASE_ASSERT(res6.unwrap() == 5);
}
static void
AndThenTest()
{
// `andThen`ing over success results.
Result<int, const char*> r1(10);
Result<int, const char*> r2 = r1.andThen([](int x) {
return Result<int, const char*>(x + 1);
});
MOZ_RELEASE_ASSERT(r2.isOk());
MOZ_RELEASE_ASSERT(r2.unwrap() == 11);
// `andThen`ing over error results.
Result<int, const char*> r3("error");
Result<int, const char*> r4 = r3.andThen([](int x) {
MOZ_RELEASE_ASSERT(false);
return Result<int, const char*>(1);
});
MOZ_RELEASE_ASSERT(r4.isErr());
MOZ_RELEASE_ASSERT(r3.unwrapErr() == r4.unwrapErr());
}
/* * */
int main()
@ -209,5 +230,6 @@ int main()
EmptyValueTest();
ReferenceTest();
MapTest();
AndThenTest();
return 0;
}