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