Imported Upstream version 1.41.0
[platform/upstream/grpc.git] / src / core / lib / promise / loop.h
1 // Copyright 2021 gRPC authors.
2 //
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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #ifndef GRPC_CORE_LIB_PROMISE_LOOP_H
16 #define GRPC_CORE_LIB_PROMISE_LOOP_H
17
18 #include <grpc/impl/codegen/port_platform.h>
19
20 #include "absl/types/variant.h"
21
22 #include "src/core/lib/promise/detail/promise_factory.h"
23
24 namespace grpc_core {
25
26 // Special type - signals to loop to take another iteration, instead of
27 // finishing
28 struct Continue {};
29
30 // Result of polling a loop promise - either Continue looping, or return a value
31 // T
32 template <typename T>
33 using LoopCtl = absl::variant<Continue, T>;
34
35 namespace promise_detail {
36
37 template <typename T>
38 struct LoopTraits;
39 template <typename T>
40 struct LoopTraits<LoopCtl<T>> {
41   using Result = T;
42 };
43
44 template <typename F>
45 class Loop {
46  private:
47   using Factory = promise_detail::PromiseFactory<void, F>;
48   using Promise = decltype(std::declval<Factory>().Repeated());
49   using PromiseResult = typename Promise::Result;
50
51  public:
52   using Result = typename LoopTraits<PromiseResult>::Result;
53
54   explicit Loop(F f) : factory_(std::move(f)), promise_(factory_.Repeated()) {}
55   ~Loop() { promise_.~Promise(); }
56
57   Poll<Result> operator()() {
58     while (true) {
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
64         //  from our factory.
65         if (absl::holds_alternative<Continue>(*p)) {
66           promise_.~Promise();
67           new (&promise_) Promise(factory_.Repeated());
68           continue;
69         }
70         //  - otherwise there's our result... return it out.
71         return absl::get<Result>(*p);
72       } else {
73         // Otherwise the inner promise was pending, so we are pending.
74         return Pending();
75       }
76     }
77   }
78
79  private:
80   GPR_NO_UNIQUE_ADDRESS Factory factory_;
81   GPR_NO_UNIQUE_ADDRESS union { GPR_NO_UNIQUE_ADDRESS Promise promise_; };
82 };
83
84 }  // namespace promise_detail
85
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.
89 template <typename F>
90 promise_detail::Loop<F> Loop(F f) {
91   return promise_detail::Loop<F>(std::move(f));
92 }
93
94 }  // namespace grpc_core
95
96 #endif  // GRPC_CORE_LIB_PROMISE_LOOP_H