diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index e09b30ba638..758f65f05b2 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -6590,10 +6590,14 @@ targets: build: test language: c++ headers: + - src/core/lib/gprpp/construct_destruct.h + - src/core/lib/promise/detail/basic_seq.h - src/core/lib/promise/detail/promise_factory.h - src/core/lib/promise/detail/promise_like.h + - src/core/lib/promise/detail/switch.h - src/core/lib/promise/loop.h - src/core/lib/promise/poll.h + - src/core/lib/promise/seq.h src: - test/core/promise/loop_test.cc deps: diff --git a/src/core/lib/promise/detail/basic_seq.h b/src/core/lib/promise/detail/basic_seq.h index 72b91f9a03d..e03bb6d475b 100644 --- a/src/core/lib/promise/detail/basic_seq.h +++ b/src/core/lib/promise/detail/basic_seq.h @@ -68,12 +68,14 @@ struct SeqState { // Move constructor - assumes we're in the initial state (move prior) as it's // illegal to move a promise after polling it. SeqState(SeqState&& other) noexcept - : prior(std::move(other.prior)), - next_factory(std::move(other.next_factory)) {} + : next_factory(std::move(other.next_factory)) { + new (&prior) PriorState(std::move(other.prior)); + } // Copy constructor - assumes we're in the initial state (move prior) as it's // illegal to move a promise after polling it. - SeqState(const SeqState& other) - : prior(other.prior), next_factory(other.next_factory) {} + SeqState(const SeqState& other) : next_factory(other.next_factory) { + new (&prior) PriorState(std::move(other.prior)); + } // Empty destructor - we instead destruct the innards in BasicSeq manually // depending on state. ~SeqState() {} @@ -115,7 +117,7 @@ struct SeqState { next_factory(other.next_factory) {} // Empty destructor - we instead destruct the innards in BasicSeq manually // depending on state. - ~SeqState(){}; + ~SeqState() {} // Evaluate the current promise, next promise factory types for this state. // Our callable is the first element of Fs, wrapped in PromiseLike to handle // some common edge cases. The next factory is the second element. diff --git a/src/core/lib/promise/loop.h b/src/core/lib/promise/loop.h index 0a5346b9fbf..8d3f6891bff 100644 --- a/src/core/lib/promise/loop.h +++ b/src/core/lib/promise/loop.h @@ -54,6 +54,13 @@ class Loop { explicit Loop(F f) : factory_(std::move(f)), promise_(factory_.Repeated()) {} ~Loop() { promise_.~Promise(); } + Loop(Loop&& loop) noexcept + : factory_(std::move(loop.factory_)), + promise_(std::move(loop.promise_)) {} + + Loop(const Loop& loop) = delete; + Loop& operator=(const Loop& loop) = delete; + Poll operator()() { while (true) { // Poll the inner promise. diff --git a/test/core/promise/BUILD b/test/core/promise/BUILD index 3382027e4c5..27358c31780 100644 --- a/test/core/promise/BUILD +++ b/test/core/promise/BUILD @@ -121,6 +121,7 @@ grpc_cc_test( uses_polling = False, deps = [ "//:loop", + "//:seq", "//test/core/util:grpc_suppressions", ], ) diff --git a/test/core/promise/loop_test.cc b/test/core/promise/loop_test.cc index 4d7b846f32b..5e6cf449517 100644 --- a/test/core/promise/loop_test.cc +++ b/test/core/promise/loop_test.cc @@ -16,6 +16,8 @@ #include +#include "src/core/lib/promise/seq.h" + namespace grpc_core { TEST(LoopTest, CountToFive) { @@ -40,6 +42,12 @@ TEST(LoopTest, FactoryCountToFive) { EXPECT_EQ(i, 5); } +TEST(LoopTest, LoopOfSeq) { + auto x = + Loop(Seq([]() { return 42; }, [](int i) -> LoopCtl { return i; }))(); + EXPECT_EQ(x, Poll(42)); +} + } // namespace grpc_core int main(int argc, char** argv) {