1 // Copyright 2021 gRPC authors.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #ifndef GRPC_CORE_LIB_PROMISE_LOOP_H
16 #define GRPC_CORE_LIB_PROMISE_LOOP_H
18 #include <grpc/impl/codegen/port_platform.h>
20 #include "absl/types/variant.h"
22 #include "src/core/lib/promise/detail/promise_factory.h"
26 // Special type - signals to loop to take another iteration, instead of
30 // Result of polling a loop promise - either Continue looping, or return a value
33 using LoopCtl = absl::variant<Continue, T>;
35 namespace promise_detail {
40 struct LoopTraits<LoopCtl<T>> {
47 using Factory = promise_detail::PromiseFactory<void, F>;
48 using Promise = decltype(std::declval<Factory>().Repeated());
49 using PromiseResult = typename Promise::Result;
52 using Result = typename LoopTraits<PromiseResult>::Result;
54 explicit Loop(F f) : factory_(std::move(f)), promise_(factory_.Repeated()) {}
55 ~Loop() { promise_.~Promise(); }
57 Poll<Result> operator()() {
59 // Poll the inner promise.
60 auto promise_result = promise_();
61 // If it returns a value:
62 if (auto* p = absl::get_if<kPollReadyIdx>(&promise_result)) {
63 // - then if it's Continue, destroy the promise and recreate a new one
65 if (absl::holds_alternative<Continue>(*p)) {
67 new (&promise_) Promise(factory_.Repeated());
70 // - otherwise there's our result... return it out.
71 return absl::get<Result>(*p);
73 // Otherwise the inner promise was pending, so we are pending.
80 GPR_NO_UNIQUE_ADDRESS Factory factory_;
81 GPR_NO_UNIQUE_ADDRESS union { GPR_NO_UNIQUE_ADDRESS Promise promise_; };
84 } // namespace promise_detail
86 // Looping combinator.
87 // Expects F returns LoopCtl<T> - if it's Continue, then run the loop again -
88 // otherwise yield the returned value as the result of the loop.
90 promise_detail::Loop<F> Loop(F f) {
91 return promise_detail::Loop<F>(std::move(f));
94 } // namespace grpc_core
96 #endif // GRPC_CORE_LIB_PROMISE_LOOP_H