/proc/self/cwd/common/values/opaque_value.h
Line | Count | Source |
1 | | // Copyright 2023 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 | | |
15 | | // IWYU pragma: private, include "common/value.h" |
16 | | // IWYU pragma: friend "common/value.h" |
17 | | // IWYU pragma: friend "common/values/optional_value.h" |
18 | | |
19 | | // `OpaqueValue` represents values of the `opaque` type. `OpaqueValueView` |
20 | | // is a non-owning view of `OpaqueValue`. `OpaqueValueInterface` is the abstract |
21 | | // base class of implementations. `OpaqueValue` and `OpaqueValueView` act as |
22 | | // smart pointers to `OpaqueValueInterface`. |
23 | | |
24 | | #ifndef THIRD_PARTY_CEL_CPP_COMMON_VALUES_OPAQUE_VALUE_H_ |
25 | | #define THIRD_PARTY_CEL_CPP_COMMON_VALUES_OPAQUE_VALUE_H_ |
26 | | |
27 | | #include <ostream> |
28 | | #include <string> |
29 | | #include <type_traits> |
30 | | #include <utility> |
31 | | |
32 | | #include "absl/base/attributes.h" |
33 | | #include "absl/base/nullability.h" |
34 | | #include "absl/log/absl_check.h" |
35 | | #include "absl/status/status.h" |
36 | | #include "absl/strings/string_view.h" |
37 | | #include "absl/types/optional.h" |
38 | | #include "common/native_type.h" |
39 | | #include "common/optional_ref.h" |
40 | | #include "common/type.h" |
41 | | #include "common/value_kind.h" |
42 | | #include "common/values/custom_value.h" |
43 | | #include "common/values/values.h" |
44 | | #include "google/protobuf/arena.h" |
45 | | #include "google/protobuf/descriptor.h" |
46 | | #include "google/protobuf/io/zero_copy_stream.h" |
47 | | #include "google/protobuf/message.h" |
48 | | |
49 | | namespace cel { |
50 | | |
51 | | class Value; |
52 | | class OpaqueValueInterface; |
53 | | class OpaqueValueInterfaceIterator; |
54 | | class OpaqueValue; |
55 | | |
56 | | using OpaqueValueContent = CustomValueContent; |
57 | | |
58 | | struct OpaqueValueDispatcher { |
59 | | using GetTypeId = |
60 | | NativeTypeId (*)(const OpaqueValueDispatcher* absl_nonnull dispatcher, |
61 | | OpaqueValueContent content); |
62 | | |
63 | | using GetArena = google::protobuf::Arena* absl_nullable (*)( |
64 | | const OpaqueValueDispatcher* absl_nonnull dispatcher, |
65 | | OpaqueValueContent content); |
66 | | |
67 | | using GetTypeName = absl::string_view (*)( |
68 | | const OpaqueValueDispatcher* absl_nonnull dispatcher, |
69 | | OpaqueValueContent content); |
70 | | |
71 | | using DebugString = |
72 | | std::string (*)(const OpaqueValueDispatcher* absl_nonnull dispatcher, |
73 | | OpaqueValueContent content); |
74 | | |
75 | | using GetRuntimeType = |
76 | | OpaqueType (*)(const OpaqueValueDispatcher* absl_nonnull dispatcher, |
77 | | OpaqueValueContent content); |
78 | | |
79 | | using Equal = absl::Status (*)( |
80 | | const OpaqueValueDispatcher* absl_nonnull dispatcher, |
81 | | OpaqueValueContent content, const OpaqueValue& other, |
82 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
83 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
84 | | google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result); |
85 | | |
86 | | using Clone = OpaqueValue (*)( |
87 | | const OpaqueValueDispatcher* absl_nonnull dispatcher, |
88 | | OpaqueValueContent content, google::protobuf::Arena* absl_nonnull arena); |
89 | | |
90 | | absl_nonnull GetTypeId get_type_id; |
91 | | |
92 | | absl_nonnull GetArena get_arena; |
93 | | |
94 | | absl_nonnull GetTypeName get_type_name; |
95 | | |
96 | | absl_nonnull DebugString debug_string; |
97 | | |
98 | | absl_nonnull GetRuntimeType get_runtime_type; |
99 | | |
100 | | absl_nonnull Equal equal; |
101 | | |
102 | | absl_nonnull Clone clone; |
103 | | }; |
104 | | |
105 | | class OpaqueValueInterface { |
106 | | public: |
107 | | OpaqueValueInterface() = default; |
108 | | OpaqueValueInterface(const OpaqueValueInterface&) = delete; |
109 | | OpaqueValueInterface(OpaqueValueInterface&&) = delete; |
110 | | |
111 | | virtual ~OpaqueValueInterface() = default; |
112 | | |
113 | | OpaqueValueInterface& operator=(const OpaqueValueInterface&) = delete; |
114 | | OpaqueValueInterface& operator=(OpaqueValueInterface&&) = delete; |
115 | | |
116 | | private: |
117 | | friend class OpaqueValue; |
118 | | |
119 | | virtual std::string DebugString() const = 0; |
120 | | |
121 | | virtual absl::string_view GetTypeName() const = 0; |
122 | | |
123 | | virtual OpaqueType GetRuntimeType() const = 0; |
124 | | |
125 | | virtual absl::Status Equal( |
126 | | const OpaqueValue& other, |
127 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
128 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
129 | | google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const = 0; |
130 | | |
131 | | virtual OpaqueValue Clone(google::protobuf::Arena* absl_nonnull arena) const = 0; |
132 | | |
133 | | virtual NativeTypeId GetNativeTypeId() const = 0; |
134 | | |
135 | | struct Content { |
136 | | const OpaqueValueInterface* absl_nonnull interface; |
137 | | google::protobuf::Arena* absl_nonnull arena; |
138 | | }; |
139 | | }; |
140 | | |
141 | | // Creates an opaque value from a manual dispatch table `dispatcher` and |
142 | | // opaque data `content` whose format is only know to functions in the manual |
143 | | // dispatch table. The dispatch table should probably be valid for the lifetime |
144 | | // of the process, but at a minimum must outlive all instances of the resulting |
145 | | // value. |
146 | | // |
147 | | // IMPORTANT: This approach to implementing OpaqueValue should only be |
148 | | // used when you know exactly what you are doing. When in doubt, just implement |
149 | | // OpaqueValueInterface. |
150 | | OpaqueValue UnsafeOpaqueValue(const OpaqueValueDispatcher* absl_nonnull |
151 | | dispatcher ABSL_ATTRIBUTE_LIFETIME_BOUND, |
152 | | OpaqueValueContent content); |
153 | | |
154 | | class OpaqueValue : private common_internal::OpaqueValueMixin<OpaqueValue> { |
155 | | public: |
156 | | static constexpr ValueKind kKind = ValueKind::kOpaque; |
157 | | |
158 | | // Constructs an opaque value from an implementation of |
159 | | // `OpaqueValueInterface` `interface` whose lifetime is tied to that of |
160 | | // the arena `arena`. |
161 | | OpaqueValue(const OpaqueValueInterface* absl_nonnull |
162 | | interface ABSL_ATTRIBUTE_LIFETIME_BOUND, |
163 | 0 | google::protobuf::Arena* absl_nonnull arena ABSL_ATTRIBUTE_LIFETIME_BOUND) { |
164 | 0 | ABSL_DCHECK(interface != nullptr); |
165 | 0 | ABSL_DCHECK(arena != nullptr); |
166 | 0 | content_ = OpaqueValueContent::From( |
167 | 0 | OpaqueValueInterface::Content{.interface = interface, .arena = arena}); |
168 | 0 | } |
169 | | |
170 | | OpaqueValue() = default; |
171 | | OpaqueValue(const OpaqueValue&) = default; |
172 | | OpaqueValue(OpaqueValue&&) = default; |
173 | | OpaqueValue& operator=(const OpaqueValue&) = default; |
174 | | OpaqueValue& operator=(OpaqueValue&&) = default; |
175 | | |
176 | 0 | static constexpr ValueKind kind() { return kKind; } |
177 | | |
178 | | NativeTypeId GetTypeId() const; |
179 | | |
180 | | OpaqueType GetRuntimeType() const; |
181 | | |
182 | | absl::string_view GetTypeName() const; |
183 | | |
184 | | std::string DebugString() const; |
185 | | |
186 | | // See Value::SerializeTo(). |
187 | | absl::Status SerializeTo( |
188 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
189 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
190 | | google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const; |
191 | | |
192 | | // See Value::ConvertToJson(). |
193 | | absl::Status ConvertToJson( |
194 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
195 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
196 | | google::protobuf::Message* absl_nonnull json) const; |
197 | | |
198 | | absl::Status Equal(const Value& other, |
199 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
200 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
201 | | google::protobuf::Arena* absl_nonnull arena, |
202 | | Value* absl_nonnull result) const; |
203 | | using OpaqueValueMixin::Equal; |
204 | | |
205 | 0 | bool IsZeroValue() const { return false; } |
206 | | |
207 | | OpaqueValue Clone(google::protobuf::Arena* absl_nonnull arena) const; |
208 | | |
209 | | // Returns `true` if this opaque value is an instance of an optional value. |
210 | | bool IsOptional() const; |
211 | | |
212 | | // Convenience method for use with template metaprogramming. See |
213 | | // `IsOptional()`. |
214 | | template <typename T> |
215 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, bool> Is() const { |
216 | | return IsOptional(); |
217 | | } |
218 | | |
219 | | // Performs a checked cast from an opaque value to an optional value, |
220 | | // returning a non-empty optional with either a value or reference to the |
221 | | // optional value. Otherwise an empty optional is returned. |
222 | | optional_ref<const OptionalValue> AsOptional() & |
223 | | ABSL_ATTRIBUTE_LIFETIME_BOUND; |
224 | | optional_ref<const OptionalValue> AsOptional() |
225 | | const& ABSL_ATTRIBUTE_LIFETIME_BOUND; |
226 | | absl::optional<OptionalValue> AsOptional() &&; |
227 | | absl::optional<OptionalValue> AsOptional() const&&; |
228 | | |
229 | | // Convenience method for use with template metaprogramming. See |
230 | | // `AsOptional()`. |
231 | | template <typename T> |
232 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, |
233 | | optional_ref<const OptionalValue>> |
234 | | As() & ABSL_ATTRIBUTE_LIFETIME_BOUND; |
235 | | template <typename T> |
236 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, |
237 | | optional_ref<const OptionalValue>> |
238 | | As() const& ABSL_ATTRIBUTE_LIFETIME_BOUND; |
239 | | template <typename T> |
240 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, |
241 | | absl::optional<OptionalValue>> |
242 | | As() &&; |
243 | | template <typename T> |
244 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, |
245 | | absl::optional<OptionalValue>> |
246 | | As() const&&; |
247 | | |
248 | | // Performs an unchecked cast from an opaque value to an optional value. In |
249 | | // debug builds a best effort is made to crash. If `IsOptional()` would return |
250 | | // false, calling this method is undefined behavior. |
251 | | const OptionalValue& GetOptional() & ABSL_ATTRIBUTE_LIFETIME_BOUND; |
252 | | const OptionalValue& GetOptional() const& ABSL_ATTRIBUTE_LIFETIME_BOUND; |
253 | | OptionalValue GetOptional() &&; |
254 | | OptionalValue GetOptional() const&&; |
255 | | |
256 | | // Convenience method for use with template metaprogramming. See |
257 | | // `Optional()`. |
258 | | template <typename T> |
259 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, const OptionalValue&> |
260 | | Get() & ABSL_ATTRIBUTE_LIFETIME_BOUND; |
261 | | template <typename T> |
262 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, const OptionalValue&> Get() |
263 | | const& ABSL_ATTRIBUTE_LIFETIME_BOUND; |
264 | | template <typename T> |
265 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, OptionalValue> Get() &&; |
266 | | template <typename T> |
267 | | std::enable_if_t<std::is_same_v<OptionalValue, T>, OptionalValue> Get() |
268 | | const&&; |
269 | | |
270 | 0 | const OpaqueValueDispatcher* absl_nullable dispatcher() const { |
271 | 0 | return dispatcher_; |
272 | 0 | } |
273 | | |
274 | 0 | OpaqueValueContent content() const { |
275 | 0 | ABSL_DCHECK(dispatcher_ != nullptr); |
276 | 0 | return content_; |
277 | 0 | } |
278 | | |
279 | 0 | const OpaqueValueInterface* absl_nullable interface() const { |
280 | 0 | if (dispatcher_ == nullptr) { |
281 | 0 | return content_.To<OpaqueValueInterface::Content>().interface; |
282 | 0 | } |
283 | 0 | return nullptr; |
284 | 0 | } |
285 | | |
286 | 0 | friend void swap(OpaqueValue& lhs, OpaqueValue& rhs) noexcept { |
287 | 0 | using std::swap; |
288 | 0 | swap(lhs.dispatcher_, rhs.dispatcher_); |
289 | 0 | swap(lhs.content_, rhs.content_); |
290 | 0 | } |
291 | | |
292 | 0 | explicit operator bool() const { |
293 | 0 | if (dispatcher_ == nullptr) { |
294 | 0 | return content_.To<OpaqueValueInterface::Content>().interface != nullptr; |
295 | 0 | } |
296 | 0 | return true; |
297 | 0 | } |
298 | | |
299 | | protected: |
300 | | OpaqueValue(const OpaqueValueDispatcher* absl_nonnull dispatcher |
301 | | ABSL_ATTRIBUTE_LIFETIME_BOUND, |
302 | | OpaqueValueContent content) |
303 | 0 | : dispatcher_(dispatcher), content_(content) { |
304 | 0 | ABSL_DCHECK(dispatcher != nullptr); |
305 | 0 | ABSL_DCHECK(dispatcher->get_type_id != nullptr); |
306 | 0 | ABSL_DCHECK(dispatcher->get_type_name != nullptr); |
307 | 0 | ABSL_DCHECK(dispatcher->clone != nullptr); |
308 | 0 | } |
309 | | |
310 | | private: |
311 | | friend class common_internal::ValueMixin<OpaqueValue>; |
312 | | friend class common_internal::OpaqueValueMixin<OpaqueValue>; |
313 | | friend OpaqueValue UnsafeOpaqueValue(const OpaqueValueDispatcher* absl_nonnull |
314 | | dispatcher ABSL_ATTRIBUTE_LIFETIME_BOUND, |
315 | | OpaqueValueContent content); |
316 | | |
317 | | const OpaqueValueDispatcher* absl_nullable dispatcher_ = nullptr; |
318 | | OpaqueValueContent content_ = OpaqueValueContent::Zero(); |
319 | | }; |
320 | | |
321 | 0 | inline std::ostream& operator<<(std::ostream& out, const OpaqueValue& type) { |
322 | 0 | return out << type.DebugString(); |
323 | 0 | } |
324 | | |
325 | | template <> |
326 | | struct NativeTypeTraits<OpaqueValue> final { |
327 | 0 | static NativeTypeId Id(const OpaqueValue& type) { return type.GetTypeId(); } |
328 | | }; |
329 | | |
330 | | inline OpaqueValue UnsafeOpaqueValue(const OpaqueValueDispatcher* absl_nonnull |
331 | | dispatcher ABSL_ATTRIBUTE_LIFETIME_BOUND, |
332 | 0 | OpaqueValueContent content) { |
333 | 0 | return OpaqueValue(dispatcher, content); |
334 | 0 | } |
335 | | |
336 | | } // namespace cel |
337 | | |
338 | | #endif // THIRD_PARTY_CEL_CPP_COMMON_VALUES_OPAQUE_VALUE_H_ |