[fit] Add functions for creating promises that complete immediately.
Added fit::make_result_promise(), fit::make_ok_promise(),
and fit::make_error_promise().
Adopted the new helpers in various places that benefit from it.
Test: fit-test
Change-Id: Id7519f2c25df8d2caff276286710051bad6ef9f1
diff --git a/garnet/public/lib/inspect/discovery/object_source.cc b/garnet/public/lib/inspect/discovery/object_source.cc
index 2d3a3ed..e14ec0a 100644
--- a/garnet/public/lib/inspect/discovery/object_source.cc
+++ b/garnet/public/lib/inspect/discovery/object_source.cc
@@ -318,8 +318,7 @@
if (status != ZX_OK || !file_ptr.is_bound()) {
FXL_LOG(WARNING) << "Failed to fdio_open and bind "
<< location.AbsoluteFilePath() << " " << status;
- return fit::make_promise(
- []() -> fit::result<ObjectSource> { return fit::error(); });
+ return fit::make_result_promise<ObjectSource>(fit::error());
}
return ObjectSource::Make(std::move(location), std::move(file_ptr), depth);
} else {
@@ -328,8 +327,7 @@
}
FXL_LOG(ERROR) << "Failed to open " << location.AbsoluteFilePath();
- return fit::make_promise(
- []() -> fit::result<ObjectSource> { return fit::error(); });
+ return fit::make_result_promise<ObjectSource>(fit::error());
}
// Consult the file system to find out how to open an inspect endpoint at the
diff --git a/garnet/tests/zircon/libdriver-integration-test/integration-test.h b/garnet/tests/zircon/libdriver-integration-test/integration-test.h
index 68a6463..08b61b0 100644
--- a/garnet/tests/zircon/libdriver-integration-test/integration-test.h
+++ b/garnet/tests/zircon/libdriver-integration-test/integration-test.h
@@ -26,7 +26,7 @@
assertion; \
}(); \
if (testing::Test::HasFatalFailure()) { \
- return fit::make_promise([]() { return fit::error(std::string("Assertion failure")); }); \
+ return fit::make_error_promise(std::string("Assertion failure")); \
} \
} while (0)
diff --git a/peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc b/peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc
index a08cf8c..20864ce 100644
--- a/peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc
+++ b/peridot/bin/sessionmgr/story/model/ledger_story_model_storage.cc
@@ -263,7 +263,7 @@
fuchsia::ledger::PageSnapshot* snapshot,
std::vector<StoryModelMutation> commands) {
// There is no shared state yet.
- return fit::make_promise([] { return fit::ok(); });
+ return fit::make_ok_promise();
}
} // namespace
@@ -313,7 +313,7 @@
// The returned promise will block until all pending mutation opertaions have
// resolved. These pending operations are also wrapped with |sequencer_| (in
// Execute()), which applies this sequential behavior to promises it wraps.
- return fit::make_promise([] { return fit::ok(); }).wrap_with(sequencer_);
+ return fit::make_ok_promise().wrap_with(sequencer_);
}
fit::promise<> LedgerStoryModelStorage::Execute(
diff --git a/peridot/bin/sessionmgr/story/model/noop_story_model_storage.cc b/peridot/bin/sessionmgr/story/model/noop_story_model_storage.cc
index 0f143ad..b77e5f2 100644
--- a/peridot/bin/sessionmgr/story/model/noop_story_model_storage.cc
+++ b/peridot/bin/sessionmgr/story/model/noop_story_model_storage.cc
@@ -11,13 +11,9 @@
NoopStoryModelStorage::NoopStoryModelStorage() = default;
NoopStoryModelStorage::~NoopStoryModelStorage() = default;
-fit::promise<> NoopStoryModelStorage::Load() {
- return fit::make_promise([] { return fit::ok(); });
-}
+fit::promise<> NoopStoryModelStorage::Load() { return fit::make_ok_promise(); }
-fit::promise<> NoopStoryModelStorage::Flush() {
- return fit::make_promise([] { return fit::ok(); });
-}
+fit::promise<> NoopStoryModelStorage::Flush() { return fit::make_ok_promise(); }
fit::promise<> NoopStoryModelStorage::Execute(
std::vector<fuchsia::modular::storymodel::StoryModelMutation> commands) {
diff --git a/peridot/bin/sessionmgr/story/model/story_model_owner_unittest.cc b/peridot/bin/sessionmgr/story/model/story_model_owner_unittest.cc
index bd33ab2..0267c24 100644
--- a/peridot/bin/sessionmgr/story/model/story_model_owner_unittest.cc
+++ b/peridot/bin/sessionmgr/story/model/story_model_owner_unittest.cc
@@ -30,13 +30,9 @@
};
std::vector<ExecuteCall> calls;
- fit::promise<> Load() override {
- return fit::make_promise([] { return fit::ok(); });
- }
+ fit::promise<> Load() override { return fit::make_ok_promise(); }
- fit::promise<> Flush() override {
- return fit::make_promise([] { return fit::ok(); });
- }
+ fit::promise<> Flush() override { return fit::make_ok_promise(); }
fit::promise<> Execute(std::vector<StoryModelMutation> commands) override {
fit::bridge<> bridge;
diff --git a/src/connectivity/network/testing/netemul/runner/sandbox.cc b/src/connectivity/network/testing/netemul/runner/sandbox.cc
index 5bdbcfa0..c126246 100644
--- a/src/connectivity/network/testing/netemul/runner/sandbox.cc
+++ b/src/connectivity/network/testing/netemul/runner/sandbox.cc
@@ -369,7 +369,7 @@
const config::Environment* config,
ConfiguringEnvironmentLauncher launcher) {
return fit::make_promise([this, config, launcher = std::move(launcher)] {
- auto prom = fit::make_promise([] { return fit::ok(); }).box();
+ auto prom = fit::make_ok_promise().box();
for (const auto& setup : config->setup()) {
prom = prom.and_then([this, setup = &setup, launcher]() {
return LaunchSetup(
diff --git a/zircon/docs/fit_promise_guide.md b/zircon/docs/fit_promise_guide.md
index b714a48..4ef9dde 100644
--- a/zircon/docs/fit_promise_guide.md
+++ b/zircon/docs/fit_promise_guide.md
@@ -303,7 +303,7 @@
if (condition) {
return MakeComplexPromise();
}
- return fit::make_promise([] { return fit::ok(); });
+ return fit::make_ok_promise(42);
});
```
diff --git a/zircon/system/ulib/fit/include/lib/fit/promise.h b/zircon/system/ulib/fit/include/lib/fit/promise.h
index 8ec7a1f..b0059b3 100644
--- a/zircon/system/ulib/fit/include/lib/fit/promise.h
+++ b/zircon/system/ulib/fit/include/lib/fit/promise.h
@@ -26,6 +26,9 @@
// a variety of combinators such as |then()|.
//
// Use |fit::make_promise()| to create a promise.
+// Use |fit::make_ok_promise()| to create a promise that immediately returns a value.
+// Use |fit::make_error_promise()| to create a promise that immediately returns an error.
+// Use |fit::make_result_promise()| to create a promise that immediately returns a result.
// Use |fit::future| to more conveniently hold a promise or its result.
// Use |fit::pending_task| to wrap a promise as a pending task for execution.
// Use |fit::executor| to execute a pending task.
@@ -857,6 +860,79 @@
std::move(handler)));
}
+// Returns an unboxed promise that immediately returns the specified result when invoked.
+//
+// This function is especially useful for returning promises from functions
+// that have multiple branches some of which complete synchronously.
+//
+// |result| is the result for the promise to return.
+//
+// See documentation of |fit::promise| for more information.
+template <typename V = void, typename E = void>
+inline promise_impl<::fit::internal::result_continuation<V, E>>
+make_result_promise(fit::result<V, E> result) {
+ return make_promise_with_continuation(
+ ::fit::internal::result_continuation<V, E>(std::move(result)));
+}
+template <typename V = void, typename E = void>
+inline promise_impl<::fit::internal::result_continuation<V, E>>
+make_result_promise(fit::ok_result<V> result) {
+ return make_promise_with_continuation(
+ ::fit::internal::result_continuation<V, E>(std::move(result)));
+}
+template <typename V = void, typename E = void>
+inline promise_impl<::fit::internal::result_continuation<V, E>>
+make_result_promise(fit::error_result<E> result) {
+ return make_promise_with_continuation(
+ ::fit::internal::result_continuation<V, E>(std::move(result)));
+}
+template <typename V = void, typename E = void>
+inline promise_impl<::fit::internal::result_continuation<V, E>>
+make_result_promise(fit::pending_result result) {
+ return make_promise_with_continuation(
+ ::fit::internal::result_continuation<V, E>(std::move(result)));
+}
+
+// Returns an unboxed promise that immediately returns the specified value when invoked.
+//
+// This function is especially useful for returning promises from functions
+// that have multiple branches some of which complete synchronously.
+//
+// |value| is the value for the promise to return.
+//
+// See documentation of |fit::promise| for more information.
+template <typename V>
+inline promise_impl<::fit::internal::result_continuation<V, void>>
+make_ok_promise(V value) {
+ return make_result_promise(fit::ok(std::move(value)));
+}
+
+// Overload of |make_ok_promise()| used when the value type is void.
+inline promise_impl<::fit::internal::result_continuation<void, void>>
+make_ok_promise() {
+ return make_result_promise(fit::ok());
+}
+
+// Returns an unboxed promise that immediately returns the specified error when invoked.
+//
+// This function is especially useful for returning promises from functions
+// that have multiple branches some of which complete synchronously.
+//
+// |error| is the error for the promise to return.
+//
+// See documentation of |fit::promise| for more information.
+template <typename E>
+inline promise_impl<::fit::internal::result_continuation<void, E>>
+make_error_promise(E error) {
+ return make_result_promise(fit::error(std::move(error)));
+}
+
+// Overload of |make_error_promise()| used when the error type is void.
+inline promise_impl<::fit::internal::result_continuation<void, void>>
+make_error_promise() {
+ return make_result_promise(fit::error());
+}
+
// Jointly evaluates zero or more promises.
// Returns a promise that produces a std::tuple<> containing the result
// of each promise once they all complete.
diff --git a/zircon/system/ulib/fit/include/lib/fit/promise_internal.h b/zircon/system/ulib/fit/include/lib/fit/promise_internal.h
index 9a162db..489d5a0 100644
--- a/zircon/system/ulib/fit/include/lib/fit/promise_internal.h
+++ b/zircon/system/ulib/fit/include/lib/fit/promise_internal.h
@@ -545,6 +545,21 @@
template <typename PromiseHandler>
using promise_continuation = context_handler_invoker<PromiseHandler>;
+// The continuation produced by |make_result_promise()|.
+template <typename V, typename E>
+class result_continuation final {
+public:
+ explicit result_continuation(::fit::result<V, E> result)
+ : result_(std::move(result)) {}
+
+ ::fit::result<V, E> operator()(::fit::context& context) {
+ return std::move(result_);
+ }
+
+private:
+ ::fit::result<V, E> result_;
+};
+
// Returns true if all arguments are true or if there are none.
inline bool all_true() {
return true;
diff --git a/zircon/system/utest/fit/promise_tests.cpp b/zircon/system/utest/fit/promise_tests.cpp
index e6f71ce..6468ab0 100644
--- a/zircon/system/utest/fit/promise_tests.cpp
+++ b/zircon/system/utest/fit/promise_tests.cpp
@@ -399,7 +399,137 @@
END_TEST;
}
-auto make_ok_promise(int value) {
+bool make_result_promise() {
+ BEGIN_TEST;
+
+ fake_context fake_context;
+
+ // Argument type: fit::result<int, char>
+ {
+ auto p = fit::make_result_promise(fit::result<int, char>(fit::ok(42)));
+ static_assert(std::is_same<int, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<char, decltype(p)::error_type>::value, "");
+ fit::result<int, char> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::ok, result.state());
+ EXPECT_EQ(42, result.value());
+ }
+
+ // Argument type: fit::ok_result<int> with inferred types
+ {
+ auto p = fit::make_result_promise(fit::ok(42));
+ static_assert(std::is_same<int, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<void, decltype(p)::error_type>::value, "");
+ fit::result<int, void> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::ok, result.state());
+ EXPECT_EQ(42, result.value());
+ }
+
+ // Argument type: fit::ok_result<int> with explicit types
+ {
+ auto p = fit::make_result_promise<int, char>(fit::ok(42));
+ static_assert(std::is_same<int, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<char, decltype(p)::error_type>::value, "");
+ fit::result<int, char> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::ok, result.state());
+ EXPECT_EQ(42, result.value());
+ }
+
+ // Argument type: fit::error_result<char> with inferred types
+ {
+ auto p = fit::make_result_promise(fit::error('x'));
+ static_assert(std::is_same<void, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<char, decltype(p)::error_type>::value, "");
+ fit::result<void, char> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::error, result.state());
+ EXPECT_EQ('x', result.error());
+ }
+
+ // Argument type: fit::error_result<char> with explicit types
+ {
+ auto p = fit::make_result_promise<int, char>(fit::error('x'));
+ static_assert(std::is_same<int, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<char, decltype(p)::error_type>::value, "");
+ fit::result<int, char> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::error, result.state());
+ EXPECT_EQ('x', result.error());
+ }
+
+ // Argument type: fit::pending_result with inferred types
+ {
+ auto p = fit::make_result_promise(fit::pending());
+ static_assert(std::is_same<void, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<void, decltype(p)::error_type>::value, "");
+ fit::result<void, void> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::pending, result.state());
+ }
+
+ // Argument type: fit::pending_result with explicit types
+ {
+ auto p = fit::make_result_promise<int, char>(fit::pending());
+ static_assert(std::is_same<int, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<char, decltype(p)::error_type>::value, "");
+ fit::result<int, char> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::pending, result.state());
+ }
+
+ END_TEST;
+}
+
+bool make_ok_promise() {
+ BEGIN_TEST;
+
+ fake_context fake_context;
+
+ // Argument type: int
+ {
+ auto p = fit::make_ok_promise(42);
+ static_assert(std::is_same<int, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<void, decltype(p)::error_type>::value, "");
+ fit::result<int, void> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::ok, result.state());
+ EXPECT_EQ(42, result.value());
+ }
+
+ // Argument type: none (void)
+ {
+ auto p = fit::make_ok_promise();
+ static_assert(std::is_same<void, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<void, decltype(p)::error_type>::value, "");
+ fit::result<void, void> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::ok, result.state());
+ }
+
+ END_TEST;
+}
+
+bool make_error_promise() {
+ BEGIN_TEST;
+
+ fake_context fake_context;
+
+ // Argument type: int
+ {
+ auto p = fit::make_error_promise('x');
+ static_assert(std::is_same<void, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<char, decltype(p)::error_type>::value, "");
+ fit::result<void, char> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::error, result.state());
+ EXPECT_EQ('x', result.error());
+ }
+
+ // Argument type: none (void)
+ {
+ auto p = fit::make_error_promise();
+ static_assert(std::is_same<void, decltype(p)::value_type>::value, "");
+ static_assert(std::is_same<void, decltype(p)::error_type>::value, "");
+ fit::result<void, void> result = p(fake_context);
+ EXPECT_EQ(fit::result_state::error, result.state());
+ }
+
+ END_TEST;
+}
+
+auto make_checked_ok_promise(int value) {
return fit::make_promise([value, count = 0]() mutable -> fit::result<int, char> {
ASSERT_CRITICAL(count == 0);
++count;
@@ -416,7 +546,7 @@
});
}
-auto make_error_promise(char error) {
+auto make_checked_error_promise(char error) {
return fit::make_promise([error, count = 0]() mutable -> fit::result<int, char> {
ASSERT_CRITICAL(count == 0);
++count;
@@ -512,7 +642,7 @@
{
uint64_t run_count = 0;
auto p =
- make_ok_promise(42)
+ make_checked_ok_promise(42)
.then([&](fit::result<int, char>& result)
-> fit::result<int, char> {
run_count++;
@@ -608,7 +738,7 @@
{
uint64_t run_count = 0;
auto p =
- make_ok_promise(42)
+ make_checked_ok_promise(42)
.and_then([&](int& value)
-> fit::result<int, char> {
run_count++;
@@ -704,7 +834,7 @@
{
uint64_t run_count = 0;
auto p =
- make_error_promise('a')
+ make_checked_error_promise('a')
.or_else([&](char& error)
-> fit::result<int, char> {
run_count++;
@@ -793,7 +923,7 @@
{
uint64_t run_count = 0;
auto p =
- make_ok_promise(42)
+ make_checked_ok_promise(42)
.inspect([&](fit::result<int, char>& result) {
ASSERT_CRITICAL(result.value() == 42);
run_count++;
@@ -922,8 +1052,8 @@
fake_context fake_context;
auto p = fit::join_promises(
- make_ok_promise(42),
- make_error_promise('x').or_else([](const char& error) {
+ make_checked_ok_promise(42),
+ make_checked_error_promise('x').or_else([](const char& error) {
return fit::error('y');
}),
make_delayed_ok_promise(55));
@@ -981,8 +1111,8 @@
fake_context fake_context;
std::vector<fit::promise<int, char>> promises;
- promises.push_back(make_ok_promise(42));
- promises.push_back(make_error_promise('x').or_else([](const char& error) {
+ promises.push_back(make_checked_ok_promise(42));
+ promises.push_back(make_checked_error_promise('x').or_else([](const char& error) {
return fit::error('y');
}));
promises.push_back(make_delayed_ok_promise(55));
@@ -1254,6 +1384,9 @@
RUN_TEST(comparison_with_nullptr)
RUN_TEST(make_promise)
RUN_TEST(make_promise_with_continuation)
+RUN_TEST(make_result_promise)
+RUN_TEST(make_ok_promise)
+RUN_TEST(make_error_promise)
RUN_TEST(then_combinator)
RUN_TEST(and_then_combinator)
RUN_TEST(or_else_combinator)