• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_SRC_CORE_LIB_PROMISE_ALL_OK_H
16 #define GRPC_SRC_CORE_LIB_PROMISE_ALL_OK_H
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include <tuple>
21 #include <variant>
22 
23 #include "absl/meta/type_traits.h"
24 #include "absl/status/status.h"
25 #include "absl/status/statusor.h"
26 #include "src/core/lib/promise/detail/join_state.h"
27 #include "src/core/lib/promise/detail/promise_factory.h"
28 #include "src/core/lib/promise/map.h"
29 #include "src/core/lib/promise/poll.h"
30 #include "src/core/lib/promise/status_flag.h"
31 
32 namespace grpc_core {
33 
34 namespace promise_detail {
35 
36 // Traits object to pass to JoinState
37 template <typename Result>
38 struct AllOkTraits {
39   template <typename T>
40   using ResultType = Result;
41   template <typename T>
IsOkAllOkTraits42   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static bool IsOk(const T& x) {
43     return IsStatusOk(x);
44   }
UnwrappedAllOkTraits45   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static Empty Unwrapped(StatusFlag) {
46     return Empty{};
47   }
UnwrappedAllOkTraits48   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static Empty Unwrapped(absl::Status) {
49     return Empty{};
50   }
51   template <typename R, typename T>
EarlyReturnAllOkTraits52   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static R EarlyReturn(T&& x) {
53     return StatusCast<R>(std::forward<T>(x));
54   }
55   template <typename... A>
FinalReturnAllOkTraits56   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION static Result FinalReturn(A&&...) {
57     return Result{};
58   }
59 };
60 
61 // Implementation of AllOk combinator.
62 template <typename Result, typename... Promises>
63 class AllOk {
64  public:
AllOk(Promises...promises)65   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION explicit AllOk(Promises... promises)
66       : state_(std::move(promises)...) {}
operator()67   GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION auto operator()() {
68     return state_.PollOnce();
69   }
70 
71  private:
72   JoinState<AllOkTraits<Result>, Promises...> state_;
73 };
74 
75 }  // namespace promise_detail
76 
77 // Run all promises.
78 // If any fail, cancel the rest and return the failure.
79 // If all succeed, return Ok.
80 template <typename Result, typename... Promises>
AllOk(Promises...promises)81 GPR_ATTRIBUTE_ALWAYS_INLINE_FUNCTION inline auto AllOk(Promises... promises) {
82   return promise_detail::AllOk<Result, Promises...>(std::move(promises)...);
83 }
84 
85 // Construct a promise for each element of the set, then run them all.
86 // If any fail, cancel the rest and return the failure.
87 // If all succeed, return Ok.
88 template <typename Result, typename Iter, typename FactoryFn>
AllOkIter(Iter begin,Iter end,FactoryFn factory_fn)89 inline auto AllOkIter(Iter begin, Iter end, FactoryFn factory_fn) {
90   using Factory =
91       promise_detail::RepeatedPromiseFactory<decltype(*begin), FactoryFn>;
92   Factory factory(std::move(factory_fn));
93   using Promise = typename Factory::Promise;
94   std::vector<Promise> promises;
95   std::vector<bool> done;
96   for (auto it = begin; it != end; ++it) {
97     promises.emplace_back(factory.Make(*it));
98     done.push_back(false);
99   }
100   return [promises = std::move(promises),
101           done = std::move(done)]() mutable -> Poll<Result> {
102     using Traits = promise_detail::AllOkTraits<Result>;
103     bool still_working = false;
104     for (size_t i = 0; i < promises.size(); ++i) {
105       if (done[i]) continue;
106       auto p = promises[i]();
107       if (auto* r = p.value_if_ready()) {
108         if (!Traits::IsOk(*r)) {
109           return Traits::template EarlyReturn<Result>(std::move(*r));
110         }
111         done[i] = true;
112       } else {
113         still_working = true;
114       }
115     }
116     if (still_working) return Pending{};
117     return Traits::FinalReturn();
118   };
119 }
120 
121 }  // namespace grpc_core
122 
123 #endif  // GRPC_SRC_CORE_LIB_PROMISE_ALL_OK_H
124