/proc/self/cwd/eval/eval/attribute_utility.cc
Line | Count | Source |
1 | | #include "eval/eval/attribute_utility.h" |
2 | | |
3 | | #include <cstdint> |
4 | | #include <string> |
5 | | #include <utility> |
6 | | |
7 | | #include "absl/status/statusor.h" |
8 | | #include "absl/types/optional.h" |
9 | | #include "absl/types/span.h" |
10 | | #include "base/attribute.h" |
11 | | #include "base/attribute_set.h" |
12 | | #include "base/function_result.h" |
13 | | #include "base/function_result_set.h" |
14 | | #include "base/internal/unknown_set.h" |
15 | | #include "common/casting.h" |
16 | | #include "common/function_descriptor.h" |
17 | | #include "common/unknown.h" |
18 | | #include "common/value.h" |
19 | | #include "eval/eval/attribute_trail.h" |
20 | | #include "eval/internal/errors.h" |
21 | | #include "internal/status_macros.h" |
22 | | #include "runtime/internal/attribute_matcher.h" |
23 | | |
24 | | namespace google::api::expr::runtime { |
25 | | |
26 | | using ::cel::Attribute; |
27 | | using ::cel::AttributePattern; |
28 | | using ::cel::AttributeSet; |
29 | | using ::cel::Cast; |
30 | | using ::cel::ErrorValue; |
31 | | using ::cel::FunctionResult; |
32 | | using ::cel::FunctionResultSet; |
33 | | using ::cel::InstanceOf; |
34 | | using ::cel::UnknownValue; |
35 | | using ::cel::Value; |
36 | | using ::cel::base_internal::UnknownSet; |
37 | | using ::cel::runtime_internal::AttributeMatcher; |
38 | | |
39 | | using Accumulator = AttributeUtility::Accumulator; |
40 | | using MatchResult = AttributeMatcher::MatchResult; |
41 | | |
42 | | DefaultAttributeMatcher::DefaultAttributeMatcher( |
43 | | absl::Span<const AttributePattern> unknown_patterns, |
44 | | absl::Span<const AttributePattern> missing_patterns) |
45 | 15.8k | : unknown_patterns_(unknown_patterns), |
46 | 15.8k | missing_patterns_(missing_patterns) {} |
47 | | |
48 | 0 | DefaultAttributeMatcher::DefaultAttributeMatcher() = default; |
49 | | |
50 | | AttributeMatcher::MatchResult MatchAgainstPatterns( |
51 | 0 | absl::Span<const AttributePattern> patterns, const Attribute& attr) { |
52 | 0 | MatchResult result = MatchResult::NONE; |
53 | 0 | for (const auto& pattern : patterns) { |
54 | 0 | auto current_match = pattern.IsMatch(attr); |
55 | 0 | if (current_match == cel::AttributePattern::MatchType::FULL) { |
56 | 0 | return MatchResult::FULL; |
57 | 0 | } |
58 | 0 | if (current_match == cel::AttributePattern::MatchType::PARTIAL) { |
59 | 0 | result = MatchResult::PARTIAL; |
60 | 0 | } |
61 | 0 | } |
62 | 0 | return result; |
63 | 0 | } |
64 | | |
65 | | DefaultAttributeMatcher::MatchResult DefaultAttributeMatcher::CheckForUnknown( |
66 | 0 | const Attribute& attr) const { |
67 | 0 | return MatchAgainstPatterns(unknown_patterns_, attr); |
68 | 0 | } |
69 | | |
70 | | DefaultAttributeMatcher::MatchResult DefaultAttributeMatcher::CheckForMissing( |
71 | 0 | const Attribute& attr) const { |
72 | 0 | return MatchAgainstPatterns(missing_patterns_, attr); |
73 | 0 | } |
74 | | |
75 | | bool AttributeUtility::CheckForMissingAttribute( |
76 | 0 | const AttributeTrail& trail) const { |
77 | 0 | if (trail.empty()) { |
78 | 0 | return false; |
79 | 0 | } |
80 | | // Missing attributes are only treated as errors if the attribute exactly |
81 | | // matches (so no guard against passing partial state to a function as with |
82 | | // unknowns). This was initially a design oversight, but is difficult to |
83 | | // change now. |
84 | 0 | return matcher_->CheckForMissing(trail.attribute()) == |
85 | 0 | AttributeMatcher::MatchResult::FULL; |
86 | 0 | } |
87 | | |
88 | | // Checks whether particular corresponds to any patterns that define unknowns. |
89 | | bool AttributeUtility::CheckForUnknown(const AttributeTrail& trail, |
90 | 0 | bool use_partial) const { |
91 | 0 | if (trail.empty()) { |
92 | 0 | return false; |
93 | 0 | } |
94 | 0 | MatchResult result = matcher_->CheckForUnknown(trail.attribute()); |
95 | |
|
96 | 0 | if (result == MatchResult::FULL || |
97 | 0 | (use_partial && result == MatchResult::PARTIAL)) { |
98 | 0 | return true; |
99 | 0 | } |
100 | 0 | return false; |
101 | 0 | } |
102 | | |
103 | | // Creates merged UnknownAttributeSet. |
104 | | // Scans over the args collection, merges any UnknownSets found in |
105 | | // it together with initial_set (if initial_set is not null). |
106 | | // Returns pointer to merged set or nullptr, if there were no sets to merge. |
107 | | absl::optional<UnknownValue> AttributeUtility::MergeUnknowns( |
108 | 0 | absl::Span<const cel::Value> args) const { |
109 | | // Empty unknown value may be used as a sentinel in some tests so need to |
110 | | // distinguish unset (nullopt) and empty(engaged empty value). |
111 | 0 | absl::optional<UnknownSet> result_set; |
112 | |
|
113 | 0 | for (const auto& value : args) { |
114 | 0 | if (!value->Is<cel::UnknownValue>()) continue; |
115 | 0 | if (!result_set.has_value()) { |
116 | 0 | result_set.emplace(); |
117 | 0 | } |
118 | 0 | const auto& current_set = value.GetUnknown(); |
119 | |
|
120 | 0 | cel::base_internal::UnknownSetAccess::Add( |
121 | 0 | *result_set, UnknownSet(current_set.attribute_set(), |
122 | 0 | current_set.function_result_set())); |
123 | 0 | } |
124 | |
|
125 | 0 | if (!result_set.has_value()) { |
126 | 0 | return std::nullopt; |
127 | 0 | } |
128 | | |
129 | 0 | return UnknownValue(cel::Unknown(result_set->unknown_attributes(), |
130 | 0 | result_set->unknown_function_results())); |
131 | 0 | } |
132 | | |
133 | | UnknownValue AttributeUtility::MergeUnknownValues( |
134 | 0 | const UnknownValue& left, const UnknownValue& right) const { |
135 | | // Empty unknown value may be used as a sentinel in some tests so need to |
136 | | // distinguish unset (nullopt) and empty(engaged empty value). |
137 | 0 | AttributeSet attributes; |
138 | 0 | FunctionResultSet function_results; |
139 | 0 | attributes.Add(left.attribute_set()); |
140 | 0 | function_results.Add(left.function_result_set()); |
141 | 0 | attributes.Add(right.attribute_set()); |
142 | 0 | function_results.Add(right.function_result_set()); |
143 | |
|
144 | 0 | return UnknownValue( |
145 | 0 | cel::Unknown(std::move(attributes), std::move(function_results))); |
146 | 0 | } |
147 | | |
148 | | // Creates merged UnknownAttributeSet. |
149 | | // Scans over the args collection, determines if there matches to unknown |
150 | | // patterns, merges attributes together with those from initial_set |
151 | | // (if initial_set is not null). |
152 | | // Returns pointer to merged set or nullptr, if there were no sets to merge. |
153 | | AttributeSet AttributeUtility::CheckForUnknowns( |
154 | 0 | absl::Span<const AttributeTrail> args, bool use_partial) const { |
155 | 0 | AttributeSet attribute_set; |
156 | |
|
157 | 0 | for (const auto& trail : args) { |
158 | 0 | if (CheckForUnknown(trail, use_partial)) { |
159 | 0 | attribute_set.Add(trail.attribute()); |
160 | 0 | } |
161 | 0 | } |
162 | |
|
163 | 0 | return attribute_set; |
164 | 0 | } |
165 | | |
166 | | // Creates merged UnknownAttributeSet. |
167 | | // Merges together attributes from UnknownAttributeSets found in the args |
168 | | // collection, attributes from attr that match unknown pattern |
169 | | // patterns, and attributes from initial_set |
170 | | // (if initial_set is not null). |
171 | | // Returns pointer to merged set or nullptr, if there were no sets to merge. |
172 | | absl::optional<UnknownValue> AttributeUtility::IdentifyAndMergeUnknowns( |
173 | | absl::Span<const cel::Value> args, absl::Span<const AttributeTrail> attrs, |
174 | 0 | bool use_partial) const { |
175 | 0 | absl::optional<UnknownSet> result_set; |
176 | | |
177 | | // Identify new unknowns by attribute patterns. |
178 | 0 | cel::AttributeSet attr_set = CheckForUnknowns(attrs, use_partial); |
179 | 0 | if (!attr_set.empty()) { |
180 | 0 | result_set.emplace(std::move(attr_set)); |
181 | 0 | } |
182 | | |
183 | | // merge down existing unknown sets |
184 | 0 | absl::optional<UnknownValue> arg_unknowns = MergeUnknowns(args); |
185 | |
|
186 | 0 | if (!result_set.has_value()) { |
187 | | // No new unknowns so no need to check for presence of existing unknowns -- |
188 | | // just forward. |
189 | 0 | return arg_unknowns; |
190 | 0 | } |
191 | | |
192 | 0 | if (arg_unknowns.has_value()) { |
193 | 0 | cel::base_internal::UnknownSetAccess::Add( |
194 | 0 | *result_set, UnknownSet((*arg_unknowns).attribute_set(), |
195 | 0 | (*arg_unknowns).function_result_set())); |
196 | 0 | } |
197 | |
|
198 | 0 | return UnknownValue(cel::Unknown(result_set->unknown_attributes(), |
199 | 0 | result_set->unknown_function_results())); |
200 | 0 | } |
201 | | |
202 | 0 | UnknownValue AttributeUtility::CreateUnknownSet(cel::Attribute attr) const { |
203 | 0 | return UnknownValue(cel::Unknown(AttributeSet({std::move(attr)}))); |
204 | 0 | } |
205 | | |
206 | | absl::StatusOr<ErrorValue> AttributeUtility::CreateMissingAttributeError( |
207 | 0 | const cel::Attribute& attr) const { |
208 | 0 | CEL_ASSIGN_OR_RETURN(std::string message, attr.AsString()); |
209 | 0 | return cel::ErrorValue( |
210 | 0 | cel::runtime_internal::CreateMissingAttributeError(message)); |
211 | 0 | } |
212 | | |
213 | | UnknownValue AttributeUtility::CreateUnknownSet( |
214 | | const cel::FunctionDescriptor& fn_descriptor, int64_t expr_id, |
215 | 0 | absl::Span<const cel::Value> args) const { |
216 | 0 | return UnknownValue( |
217 | 0 | cel::Unknown(FunctionResultSet(FunctionResult(fn_descriptor, expr_id)))); |
218 | 0 | } |
219 | | |
220 | 0 | void AttributeUtility::Add(Accumulator& a, const cel::UnknownValue& v) const { |
221 | 0 | a.attribute_set_.Add(v.attribute_set()); |
222 | 0 | a.function_result_set_.Add(v.function_result_set()); |
223 | 0 | } |
224 | | |
225 | 0 | void AttributeUtility::Add(Accumulator& a, const AttributeTrail& attr) const { |
226 | 0 | a.attribute_set_.Add(attr.attribute()); |
227 | 0 | } |
228 | | |
229 | 0 | void Accumulator::Add(const UnknownValue& value) { |
230 | 0 | unknown_present_ = true; |
231 | 0 | parent_.Add(*this, value); |
232 | 0 | } |
233 | | |
234 | 0 | void Accumulator::Add(const AttributeTrail& attr) { parent_.Add(*this, attr); } |
235 | | |
236 | 0 | void Accumulator::MaybeAdd(const Value& v) { |
237 | 0 | if (v.IsUnknown()) { |
238 | 0 | Add(v.GetUnknown()); |
239 | 0 | } |
240 | 0 | } |
241 | | |
242 | 0 | void Accumulator::MaybeAdd(const Value& v, const AttributeTrail& attr) { |
243 | 0 | if (v.IsUnknown()) { |
244 | 0 | Add(v.GetUnknown()); |
245 | 0 | } else if (parent_.CheckForUnknown(attr, /*use_partial=*/true)) { |
246 | 0 | Add(attr); |
247 | 0 | } |
248 | 0 | } |
249 | | |
250 | 0 | bool Accumulator::IsEmpty() const { |
251 | 0 | return !unknown_present_ && attribute_set_.empty() && |
252 | 0 | function_result_set_.empty(); |
253 | 0 | } |
254 | | |
255 | 0 | cel::UnknownValue Accumulator::Build() && { |
256 | 0 | return cel::UnknownValue( |
257 | 0 | cel::Unknown(std::move(attribute_set_), std::move(function_result_set_))); |
258 | 0 | } |
259 | | |
260 | | } // namespace google::api::expr::runtime |