зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1661084 - Add CollectWhile/CollectEach algorithms for Result. r=janv
Differential Revision: https://phabricator.services.mozilla.com/D88169
This commit is contained in:
Родитель
a7f224accb
Коммит
fccf1a2cc3
|
@ -611,6 +611,54 @@ Result<R, nsresult> ToResultGet(const Func& aFunc, Args&&... aArgs) {
|
|||
return res;
|
||||
}
|
||||
|
||||
// Like Rust's collect with a step function, not a generic iterator/range.
|
||||
//
|
||||
// Cond must be a function type with a return type to Result<V, E>, where
|
||||
// V is convertible to bool
|
||||
// - success converts to true indicates that collection shall continue
|
||||
// - success converts to false indicates that collection is completed
|
||||
// - error indicates that collection shall stop, propagating the error
|
||||
//
|
||||
// Body must a function type accepting a V xvalue with a return type convertible
|
||||
// to Result<empty, E>.
|
||||
template <typename Step, typename Body>
|
||||
auto CollectEach(const Step& aStep, const Body& aBody)
|
||||
-> Result<mozilla::Ok, typename std::result_of_t<Step()>::err_type> {
|
||||
using StepResultType = typename std::result_of_t<Step()>::ok_type;
|
||||
|
||||
static_assert(std::is_empty_v<
|
||||
typename std::result_of_t<Body(StepResultType &&)>::ok_type>);
|
||||
|
||||
while (true) {
|
||||
StepResultType element;
|
||||
MOZ_TRY_VAR(element, aStep());
|
||||
|
||||
if (!static_cast<bool>(element)) {
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_TRY(aBody(std::move(element)));
|
||||
}
|
||||
|
||||
return mozilla::Ok{};
|
||||
}
|
||||
|
||||
// Like Rust's collect with a while loop, not a generic iterator/range.
|
||||
//
|
||||
// Cond must be a function type accepting no parameters with a return type
|
||||
// convertible to Result<bool, E>, where
|
||||
// - success true indicates that collection shall continue
|
||||
// - success false indicates that collection is completed
|
||||
// - error indicates that collection shall stop, propagating the error
|
||||
//
|
||||
// Body must a function type accepting no parameters with a return type
|
||||
// convertible to Result<empty, E>.
|
||||
template <typename Cond, typename Body>
|
||||
auto CollectWhile(const Cond& aCond, const Body& aBody)
|
||||
-> Result<mozilla::Ok, typename std::result_of_t<Cond()>::err_type> {
|
||||
return CollectEach(aCond, [&aBody](bool) { return aBody(); });
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
namespace quota {
|
||||
|
||||
|
|
|
@ -491,3 +491,121 @@ TEST(QuotaCommon_ToResultGet, Lambda_WithInput_Err)
|
|||
EXPECT_TRUE(res.isErr());
|
||||
EXPECT_EQ(res.unwrapErr(), NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// BEGIN COPY FROM mfbt/tests/TestResult.cpp
|
||||
struct Failed {
|
||||
int x;
|
||||
};
|
||||
|
||||
static GenericErrorResult<Failed&> Fail() {
|
||||
static Failed failed;
|
||||
return Err<Failed&>(failed);
|
||||
}
|
||||
|
||||
static Result<Ok, Failed&> Task1(bool pass) {
|
||||
if (!pass) {
|
||||
return Fail(); // implicit conversion from GenericErrorResult to Result
|
||||
}
|
||||
return Ok();
|
||||
}
|
||||
// END COPY FROM mfbt/tests/TestResult.cpp
|
||||
|
||||
static Result<bool, Failed&> Condition(bool aNoError, bool aResult) {
|
||||
return Task1(aNoError).map([aResult](auto) { return aResult; });
|
||||
}
|
||||
|
||||
TEST(QuotaCommon_CollectWhileTest, NoFailures)
|
||||
{
|
||||
const size_t loopCount = 5;
|
||||
size_t conditionExecutions = 0;
|
||||
size_t bodyExecutions = 0;
|
||||
auto result = CollectWhile(
|
||||
[&conditionExecutions] {
|
||||
++conditionExecutions;
|
||||
return Condition(true, conditionExecutions <= loopCount);
|
||||
},
|
||||
[&bodyExecutions] {
|
||||
++bodyExecutions;
|
||||
return Task1(true);
|
||||
});
|
||||
static_assert(std::is_same_v<decltype(result), Result<Ok, Failed&>>);
|
||||
MOZ_RELEASE_ASSERT(result.isOk());
|
||||
MOZ_RELEASE_ASSERT(loopCount == bodyExecutions);
|
||||
MOZ_RELEASE_ASSERT(1 + loopCount == conditionExecutions);
|
||||
}
|
||||
|
||||
TEST(QuotaCommon_CollectWhileTest, BodyFailsImmediately)
|
||||
{
|
||||
size_t conditionExecutions = 0;
|
||||
size_t bodyExecutions = 0;
|
||||
auto result = CollectWhile(
|
||||
[&conditionExecutions] {
|
||||
++conditionExecutions;
|
||||
return Condition(true, true);
|
||||
},
|
||||
[&bodyExecutions] {
|
||||
++bodyExecutions;
|
||||
return Task1(false);
|
||||
});
|
||||
static_assert(std::is_same_v<decltype(result), Result<Ok, Failed&>>);
|
||||
MOZ_RELEASE_ASSERT(result.isErr());
|
||||
MOZ_RELEASE_ASSERT(1 == bodyExecutions);
|
||||
MOZ_RELEASE_ASSERT(1 == conditionExecutions);
|
||||
}
|
||||
|
||||
TEST(QuotaCommon_CollectWhileTest, BodyFailsOnSecondExecution)
|
||||
{
|
||||
size_t conditionExecutions = 0;
|
||||
size_t bodyExecutions = 0;
|
||||
auto result = CollectWhile(
|
||||
[&conditionExecutions] {
|
||||
++conditionExecutions;
|
||||
return Condition(true, true);
|
||||
},
|
||||
[&bodyExecutions] {
|
||||
++bodyExecutions;
|
||||
return Task1(bodyExecutions < 2);
|
||||
});
|
||||
static_assert(std::is_same_v<decltype(result), Result<Ok, Failed&>>);
|
||||
MOZ_RELEASE_ASSERT(result.isErr());
|
||||
MOZ_RELEASE_ASSERT(2 == bodyExecutions);
|
||||
MOZ_RELEASE_ASSERT(2 == conditionExecutions);
|
||||
}
|
||||
|
||||
TEST(QuotaCommon_CollectWhileTest, ConditionFailsImmediately)
|
||||
{
|
||||
size_t conditionExecutions = 0;
|
||||
size_t bodyExecutions = 0;
|
||||
auto result = CollectWhile(
|
||||
[&conditionExecutions] {
|
||||
++conditionExecutions;
|
||||
return Condition(false, true);
|
||||
},
|
||||
[&bodyExecutions] {
|
||||
++bodyExecutions;
|
||||
return Task1(true);
|
||||
});
|
||||
static_assert(std::is_same_v<decltype(result), Result<Ok, Failed&>>);
|
||||
MOZ_RELEASE_ASSERT(result.isErr());
|
||||
MOZ_RELEASE_ASSERT(0 == bodyExecutions);
|
||||
MOZ_RELEASE_ASSERT(1 == conditionExecutions);
|
||||
}
|
||||
|
||||
TEST(QuotaCommon_CollectWhileTest, ConditionFailsOnSecondExecution)
|
||||
{
|
||||
size_t conditionExecutions = 0;
|
||||
size_t bodyExecutions = 0;
|
||||
auto result = CollectWhile(
|
||||
[&conditionExecutions] {
|
||||
++conditionExecutions;
|
||||
return Condition(conditionExecutions < 2, true);
|
||||
},
|
||||
[&bodyExecutions] {
|
||||
++bodyExecutions;
|
||||
return Task1(true);
|
||||
});
|
||||
static_assert(std::is_same_v<decltype(result), Result<Ok, Failed&>>);
|
||||
MOZ_RELEASE_ASSERT(result.isErr());
|
||||
MOZ_RELEASE_ASSERT(1 == bodyExecutions);
|
||||
MOZ_RELEASE_ASSERT(2 == conditionExecutions);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче