Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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_