1 // Copyright 2020 Google LLC
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 // https://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 #ifndef GOOGLE_CLOUD_CPP_GENERATOR_INTERNAL_PREDICATE_UTILS_H
15 #define GOOGLE_CLOUD_CPP_GENERATOR_INTERNAL_PREDICATE_UTILS_H
16
17 #include "google/cloud/optional.h"
18 #include <google/protobuf/descriptor.h>
19 #include <functional>
20 #include <vector>
21
22 namespace google {
23 namespace cloud {
24 namespace generator_internal {
25
26 /**
27 * Determines if the given method meets the criteria for pagination.
28 *
29 * https://google.aip.dev/client-libraries/4233
30 */
31 bool IsPaginated(google::protobuf::MethodDescriptor const& method);
32
33 /**
34 * Determines if the given method has neither client-side streaming, server-side
35 * streaming, nor bidirectional streaming.
36 */
37 bool IsNonStreaming(google::protobuf::MethodDescriptor const& method);
38
39 /**
40 * Determines if the given method is a long running operation.
41 */
42 bool IsLongrunningOperation(google::protobuf::MethodDescriptor const& method);
43
44 /**
45 * Determines if the given method returns `google::protobug::Empty`.
46 */
47 bool IsResponseTypeEmpty(google::protobuf::MethodDescriptor const& method);
48
49 /**
50 * Determines if the given method's response is contained in the longrunning
51 * metadata field.
52 */
53 bool IsLongrunningMetadataTypeUsedAsResponse(
54 google::protobuf::MethodDescriptor const& method);
55 /**
56 * If method meets pagination criteria, provides paginated field type and field
57 * name.
58 *
59 * https://google.aip.dev/client-libraries/4233
60 */
61 google::cloud::optional<std::pair<std::string, std::string>>
62 DeterminePagination(google::protobuf::MethodDescriptor const& method);
63
64 /**
65 * Returns true if all predicates return true.
66 */
67 template <typename T, typename... Ps>
GenericAll(Ps &&...p)68 std::function<bool(T const&)> GenericAll(Ps&&... p) {
69 using function = std::function<bool(T const&)>;
70 std::vector<function> predicates({std::forward<Ps>(p)...});
71 return [predicates](T const& m) {
72 return std::all_of(predicates.begin(), predicates.end(),
73 [&m](function const& p) { return p(m); });
74 };
75 }
76
77 template <typename... Ps>
All(Ps &&...p)78 std::function<bool(google::protobuf::MethodDescriptor const&)> All(Ps&&... p) {
79 return GenericAll<google::protobuf::MethodDescriptor, Ps...>(
80 std::forward<Ps>(p)...);
81 }
82
83 /**
84 * Returns true if any predicate returns true.
85 * @tparam T
86 */
87 template <typename T, typename... Ps>
GenericAny(Ps &&...p)88 std::function<bool(T const&)> GenericAny(Ps&&... p) {
89 using function = std::function<bool(T const&)>;
90 std::vector<function> predicates({std::forward<Ps>(p)...});
91 return [predicates](T const& m) {
92 return std::any_of(predicates.begin(), predicates.end(),
93 [&m](function const& p) { return p(m); });
94 };
95 }
96
97 template <typename... Ps>
Any(Ps &&...p)98 std::function<bool(google::protobuf::MethodDescriptor const&)> Any(Ps&&... p) {
99 return GenericAny<google::protobuf::MethodDescriptor, Ps...>(
100 std::forward<Ps>(p)...);
101 }
102
103 /**
104 * Returns true if both predicates return true.
105 */
106 template <typename T>
GenericAnd(std::function<bool (T const &)> const & lhs,std::function<bool (T const &)> const & rhs)107 std::function<bool(T const&)> GenericAnd(
108 std::function<bool(T const&)> const& lhs,
109 std::function<bool(T const&)> const& rhs) {
110 return [lhs, rhs](T const& m) -> bool { return lhs(m) && rhs(m); };
111 }
112
And(std::function<bool (google::protobuf::MethodDescriptor const &)> const & lhs,std::function<bool (google::protobuf::MethodDescriptor const &)> const & rhs)113 inline std::function<bool(google::protobuf::MethodDescriptor const&)> And(
114 std::function<bool(google::protobuf::MethodDescriptor const&)> const& lhs,
115 std::function<bool(google::protobuf::MethodDescriptor const&)> const& rhs) {
116 return GenericAnd(lhs, rhs);
117 }
118
119 /**
120 * Returns true if either predicate returns true.
121 */
122 template <typename T>
GenericOr(std::function<bool (T const &)> const & lhs,std::function<bool (T const &)> const & rhs)123 std::function<bool(T const&)> GenericOr(
124 std::function<bool(T const&)> const& lhs,
125 std::function<bool(T const&)> const& rhs) {
126 return [lhs, rhs](T const& m) -> bool { return lhs(m) || rhs(m); };
127 }
128
Or(std::function<bool (google::protobuf::MethodDescriptor const &)> const & lhs,std::function<bool (google::protobuf::MethodDescriptor const &)> const & rhs)129 inline std::function<bool(google::protobuf::MethodDescriptor const&)> Or(
130 std::function<bool(google::protobuf::MethodDescriptor const&)> const& lhs,
131 std::function<bool(google::protobuf::MethodDescriptor const&)> const& rhs) {
132 return GenericOr(lhs, rhs);
133 }
134
135 /**
136 * Predicate negation operation.
137 */
138 template <typename T>
GenericNot(std::function<bool (T const &)> const & p)139 std::function<bool(T const&)> GenericNot(
140 std::function<bool(T const&)> const& p) {
141 return [p](T const& m) -> bool { return !p(m); };
142 }
143
Not(std::function<bool (google::protobuf::MethodDescriptor const &)> const & p)144 inline std::function<bool(google::protobuf::MethodDescriptor const&)> Not(
145 std::function<bool(google::protobuf::MethodDescriptor const&)> const& p) {
146 return GenericNot(p);
147 }
148
149 /**
150 * When provided with two strings and a predicate, returns one of the strings
151 * based on evaluation of predicate.
152 *
153 * When provided with one string, always returns the string.
154 */
155 template <typename T>
156 class PredicatedFragment {
157 public:
158 using PredicateFn = std::function<bool(T const&)>;
159
PredicatedFragment(PredicateFn predicate,std::string fragment_if_true,std::string fragment_if_false)160 PredicatedFragment(PredicateFn predicate, std::string fragment_if_true,
161 std::string fragment_if_false)
162 : predicate_(std::move(predicate)),
163 fragment_if_true_(std::move(fragment_if_true)),
164 fragment_if_false_(std::move(fragment_if_false)) {}
165
PredicatedFragment(std::string fragment_always_true)166 PredicatedFragment(std::string fragment_always_true) // NOLINT
167 : predicate_([](T const&) { return true; }),
168 fragment_if_true_(std::move(fragment_always_true)),
169 fragment_if_false_({}) {}
170
operator()171 std::string operator()(T const& descriptor) const {
172 if (predicate_(descriptor)) {
173 return fragment_if_true_;
174 }
175 return fragment_if_false_;
176 }
177
178 private:
179 PredicateFn predicate_;
180 std::string fragment_if_true_;
181 std::string fragment_if_false_;
182 };
183
184 template <typename T>
185 class Pattern {
186 public:
Pattern(std::vector<PredicatedFragment<T>> f,std::function<bool (T const &)> p)187 Pattern(std::vector<PredicatedFragment<T>> f, std::function<bool(T const&)> p)
188 : fragments_(std::move(f)), predicate_(std::move(p)) {}
189
operator()190 bool operator()(T const& p) const { return predicate_(p); }
fragments()191 std::vector<PredicatedFragment<T>> const& fragments() const {
192 return fragments_;
193 }
194
195 private:
196 std::vector<PredicatedFragment<T>> fragments_;
197 std::function<bool(T const&)> predicate_;
198 };
199
200 using MethodPattern = Pattern<google::protobuf::MethodDescriptor>;
201
202 } // namespace generator_internal
203 } // namespace cloud
204 } // namespace google
205
206 #endif // GOOGLE_CLOUD_CPP_GENERATOR_INTERNAL_PREDICATE_UTILS_H
207