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/struct_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
18
// `StructValue` is the value representation of `StructType`. `StructValue`
19
// itself is a composed type of more specific runtime representations.
20
21
#ifndef THIRD_PARTY_CEL_CPP_COMMON_VALUES_STRUCT_VALUE_H_
22
#define THIRD_PARTY_CEL_CPP_COMMON_VALUES_STRUCT_VALUE_H_
23
24
#include <cstdint>
25
#include <memory>
26
#include <ostream>
27
#include <string>
28
#include <type_traits>
29
#include <utility>
30
31
#include "absl/base/attributes.h"
32
#include "absl/base/nullability.h"
33
#include "absl/meta/type_traits.h"
34
#include "absl/status/status.h"
35
#include "absl/status/statusor.h"
36
#include "absl/strings/string_view.h"
37
#include "absl/types/optional.h"
38
#include "absl/types/span.h"
39
#include "absl/utility/utility.h"
40
#include "base/attribute.h"
41
#include "common/native_type.h"
42
#include "common/optional_ref.h"
43
#include "common/type.h"
44
#include "common/value_kind.h"
45
#include "common/values/custom_struct_value.h"
46
#include "common/values/legacy_struct_value.h"
47
#include "common/values/message_value.h"
48
#include "common/values/parsed_message_value.h"
49
#include "common/values/struct_value_variant.h"
50
#include "common/values/values.h"
51
#include "runtime/runtime_options.h"
52
#include "google/protobuf/arena.h"
53
#include "google/protobuf/descriptor.h"
54
#include "google/protobuf/io/zero_copy_stream.h"
55
#include "google/protobuf/message.h"
56
57
namespace cel {
58
59
class StructValue;
60
class Value;
61
62
class StructValue final
63
    : private common_internal::StructValueMixin<StructValue> {
64
 public:
65
  static constexpr ValueKind kKind = ValueKind::kStruct;
66
67
  template <
68
      typename T,
69
      typename = std::enable_if_t<
70
          common_internal::IsStructValueAlternativeV<absl::remove_cvref_t<T>>>>
71
  // NOLINTNEXTLINE(google-explicit-constructor)
72
  StructValue(T&& value)
73
284
      : variant_(absl::in_place_type<absl::remove_cvref_t<T>>,
74
284
                 std::forward<T>(value)) {}
Unexecuted instantiation: cel::StructValue::StructValue<cel::ParsedMessageValue const&, void>(cel::ParsedMessageValue const&)
Unexecuted instantiation: cel::StructValue::StructValue<cel::CustomStructValue const&, void>(cel::CustomStructValue const&)
Unexecuted instantiation: cel::StructValue::StructValue<cel::ParsedMessageValue, void>(cel::ParsedMessageValue&&)
Unexecuted instantiation: cel::StructValue::StructValue<cel::common_internal::LegacyStructValue, void>(cel::common_internal::LegacyStructValue&&)
cel::StructValue::StructValue<cel::common_internal::LegacyStructValue const&, void>(cel::common_internal::LegacyStructValue const&)
Line
Count
Source
73
284
      : variant_(absl::in_place_type<absl::remove_cvref_t<T>>,
74
284
                 std::forward<T>(value)) {}
Unexecuted instantiation: cel::StructValue::StructValue<cel::CustomStructValue, void>(cel::CustomStructValue&&)
75
76
  // NOLINTNEXTLINE(google-explicit-constructor)
77
  StructValue(const MessageValue& other)
78
0
      : variant_(other.ToStructValueVariant()) {}
79
80
  // NOLINTNEXTLINE(google-explicit-constructor)
81
  StructValue(MessageValue&& other)
82
0
      : variant_(std::move(other).ToStructValueVariant()) {}
83
84
0
  StructValue() = default;
85
  StructValue(const StructValue&) = default;
86
  StructValue(StructValue&& other) = default;
87
  StructValue& operator=(const StructValue&) = default;
88
  StructValue& operator=(StructValue&&) = default;
89
90
0
  constexpr ValueKind kind() const { return kKind; }
91
92
  StructType GetRuntimeType() const;
93
94
  absl::string_view GetTypeName() const;
95
96
  NativeTypeId GetTypeId() const;
97
98
  std::string DebugString() const;
99
100
  // See Value::SerializeTo().
101
  absl::Status SerializeTo(
102
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
103
      google::protobuf::MessageFactory* absl_nonnull message_factory,
104
      google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const;
105
106
  // See Value::ConvertToJson().
107
  absl::Status ConvertToJson(
108
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
109
      google::protobuf::MessageFactory* absl_nonnull message_factory,
110
      google::protobuf::Message* absl_nonnull json) const;
111
112
  // Like ConvertToJson(), except `json` **MUST** be an instance of
113
  // `google.protobuf.Struct`.
114
  absl::Status ConvertToJsonObject(
115
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
116
      google::protobuf::MessageFactory* absl_nonnull message_factory,
117
      google::protobuf::Message* absl_nonnull json) const;
118
119
  absl::Status Equal(const Value& other,
120
                     const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
121
                     google::protobuf::MessageFactory* absl_nonnull message_factory,
122
                     google::protobuf::Arena* absl_nonnull arena,
123
                     Value* absl_nonnull result) const;
124
  using StructValueMixin::Equal;
125
126
  bool IsZeroValue() const;
127
128
  absl::Status GetFieldByName(
129
      absl::string_view name, ProtoWrapperTypeOptions unboxing_options,
130
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
131
      google::protobuf::MessageFactory* absl_nonnull message_factory,
132
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const;
133
  using StructValueMixin::GetFieldByName;
134
135
  absl::Status GetFieldByNumber(
136
      int64_t number, ProtoWrapperTypeOptions unboxing_options,
137
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
138
      google::protobuf::MessageFactory* absl_nonnull message_factory,
139
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const;
140
  using StructValueMixin::GetFieldByNumber;
141
142
  absl::StatusOr<bool> HasFieldByName(absl::string_view name) const;
143
144
  absl::StatusOr<bool> HasFieldByNumber(int64_t number) const;
145
146
  using ForEachFieldCallback = CustomStructValueInterface::ForEachFieldCallback;
147
148
  absl::Status ForEachField(
149
      ForEachFieldCallback callback,
150
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
151
      google::protobuf::MessageFactory* absl_nonnull message_factory,
152
      google::protobuf::Arena* absl_nonnull arena) const;
153
154
  absl::Status Qualify(
155
      absl::Span<const SelectQualifier> qualifiers, bool presence_test,
156
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
157
      google::protobuf::MessageFactory* absl_nonnull message_factory,
158
      google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
159
      int* absl_nonnull count) const;
160
  using StructValueMixin::Qualify;
161
162
  // Returns `true` if this value is an instance of a message value. If `true`
163
  // is returned, it is implied that `IsOpaque()` would also return true.
164
0
  bool IsMessage() const { return IsParsedMessage(); }
165
166
  // Returns `true` if this value is an instance of a parsed message value. If
167
  // `true` is returned, it is implied that `IsMessage()` would also return
168
  // true.
169
0
  bool IsParsedMessage() const { return variant_.Is<ParsedMessageValue>(); }
170
171
  // Convenience method for use with template metaprogramming. See
172
  // `IsMessage()`.
173
  template <typename T>
174
  std::enable_if_t<std::is_same_v<MessageValue, T>, bool> Is() const {
175
    return IsMessage();
176
  }
177
178
  // Convenience method for use with template metaprogramming. See
179
  // `IsParsedMessage()`.
180
  template <typename T>
181
  std::enable_if_t<std::is_same_v<ParsedMessageValue, T>, bool> Is() const {
182
    return IsParsedMessage();
183
  }
184
185
  // Performs a checked cast from a value to a message value,
186
  // returning a non-empty optional with either a value or reference to the
187
  // message value. Otherwise an empty optional is returned.
188
0
  absl::optional<MessageValue> AsMessage() & {
189
0
    return std::as_const(*this).AsMessage();
190
0
  }
191
  absl::optional<MessageValue> AsMessage() const&;
192
  absl::optional<MessageValue> AsMessage() &&;
193
0
  absl::optional<MessageValue> AsMessage() const&& { return AsMessage(); }
194
195
  // Performs a checked cast from a value to a parsed message value,
196
  // returning a non-empty optional with either a value or reference to the
197
  // parsed message value. Otherwise an empty optional is returned.
198
  optional_ref<const ParsedMessageValue> AsParsedMessage() &
199
0
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
200
0
    return std::as_const(*this).AsParsedMessage();
201
0
  }
202
  optional_ref<const ParsedMessageValue> AsParsedMessage()
203
      const& ABSL_ATTRIBUTE_LIFETIME_BOUND;
204
  absl::optional<ParsedMessageValue> AsParsedMessage() &&;
205
0
  absl::optional<ParsedMessageValue> AsParsedMessage() const&& {
206
0
    return common_internal::AsOptional(AsParsedMessage());
207
0
  }
208
209
  // Convenience method for use with template metaprogramming. See
210
  // `AsMessage()`.
211
  template <typename T>
212
  std::enable_if_t<std::is_same_v<MessageValue, T>,
213
                   absl::optional<MessageValue>>
214
  As() & {
215
    return AsMessage();
216
  }
217
  template <typename T>
218
  std::enable_if_t<std::is_same_v<MessageValue, T>,
219
                   absl::optional<MessageValue>>
220
  As() const& {
221
    return AsMessage();
222
  }
223
  template <typename T>
224
  std::enable_if_t<std::is_same_v<MessageValue, T>,
225
                   absl::optional<MessageValue>>
226
  As() && {
227
    return std::move(*this).AsMessage();
228
  }
229
  template <typename T>
230
  std::enable_if_t<std::is_same_v<MessageValue, T>,
231
                   absl::optional<MessageValue>>
232
  As() const&& {
233
    return std::move(*this).AsMessage();
234
  }
235
236
  // Convenience method for use with template metaprogramming. See
237
  // `AsParsedMessage()`.
238
  template <typename T>
239
      std::enable_if_t<std::is_same_v<ParsedMessageValue, T>,
240
                       optional_ref<const ParsedMessageValue>>
241
      As() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
242
    return AsParsedMessage();
243
  }
244
  template <typename T>
245
  std::enable_if_t<std::is_same_v<ParsedMessageValue, T>,
246
                   optional_ref<const ParsedMessageValue>>
247
  As() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
248
    return AsParsedMessage();
249
  }
250
  template <typename T>
251
  std::enable_if_t<std::is_same_v<ParsedMessageValue, T>,
252
                   absl::optional<ParsedMessageValue>>
253
  As() && {
254
    return std::move(*this).AsParsedMessage();
255
  }
256
  template <typename T>
257
  std::enable_if_t<std::is_same_v<ParsedMessageValue, T>,
258
                   absl::optional<ParsedMessageValue>>
259
  As() const&& {
260
    return std::move(*this).AsParsedMessage();
261
  }
262
263
  // Performs an unchecked cast from a value to a message value. In
264
  // debug builds a best effort is made to crash. If `IsMessage()` would return
265
  // false, calling this method is undefined behavior.
266
0
  MessageValue GetMessage() & { return std::as_const(*this).GetMessage(); }
267
  MessageValue GetMessage() const&;
268
  MessageValue GetMessage() &&;
269
0
  MessageValue GetMessage() const&& { return GetMessage(); }
270
271
  // Performs an unchecked cast from a value to a parsed message value. In
272
  // debug builds a best effort is made to crash. If `IsParsedMessage()` would
273
  // return false, calling this method is undefined behavior.
274
0
  const ParsedMessageValue& GetParsedMessage() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
275
0
    return std::as_const(*this).GetParsedMessage();
276
0
  }
277
  const ParsedMessageValue& GetParsedMessage()
278
      const& ABSL_ATTRIBUTE_LIFETIME_BOUND;
279
  ParsedMessageValue GetParsedMessage() &&;
280
0
  ParsedMessageValue GetParsedMessage() const&& { return GetParsedMessage(); }
281
282
  // Convenience method for use with template metaprogramming. See
283
  // `GetMessage()`.
284
  template <typename T>
285
  std::enable_if_t<std::is_same_v<MessageValue, T>, MessageValue> Get() & {
286
    return GetMessage();
287
  }
288
  template <typename T>
289
  std::enable_if_t<std::is_same_v<MessageValue, T>, MessageValue> Get() const& {
290
    return GetMessage();
291
  }
292
  template <typename T>
293
  std::enable_if_t<std::is_same_v<MessageValue, T>, MessageValue> Get() && {
294
    return std::move(*this).GetMessage();
295
  }
296
  template <typename T>
297
  std::enable_if_t<std::is_same_v<MessageValue, T>, MessageValue> Get()
298
      const&& {
299
    return std::move(*this).GetMessage();
300
  }
301
302
  // Convenience method for use with template metaprogramming. See
303
  // `GetParsedMessage()`.
304
  template <typename T>
305
      std::enable_if_t<std::is_same_v<ParsedMessageValue, T>,
306
                       const ParsedMessageValue&>
307
      Get() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
308
    return GetParsedMessage();
309
  }
310
  template <typename T>
311
  std::enable_if_t<std::is_same_v<ParsedMessageValue, T>,
312
                   const ParsedMessageValue&>
313
  Get() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
314
    return GetParsedMessage();
315
  }
316
  template <typename T>
317
  std::enable_if_t<std::is_same_v<ParsedMessageValue, T>, ParsedMessageValue>
318
  Get() && {
319
    return std::move(*this).GetParsedMessage();
320
  }
321
  template <typename T>
322
  std::enable_if_t<std::is_same_v<ParsedMessageValue, T>, ParsedMessageValue>
323
  Get() const&& {
324
    return std::move(*this).GetParsedMessage();
325
  }
326
327
0
  friend void swap(StructValue& lhs, StructValue& rhs) noexcept {
328
0
    using std::swap;
329
0
    swap(lhs.variant_, rhs.variant_);
330
0
  }
331
332
 private:
333
  friend class Value;
334
  friend class common_internal::ValueMixin<StructValue>;
335
  friend class common_internal::StructValueMixin<StructValue>;
336
337
  common_internal::ValueVariant ToValueVariant() const&;
338
  common_internal::ValueVariant ToValueVariant() &&;
339
340
  // Unlike many of the other derived values, `StructValue` is itself a composed
341
  // type. This is to avoid making `StructValue` too big and by extension
342
  // `Value` too big. Instead we store the derived `StructValue` values in
343
  // `Value` and not `StructValue` itself.
344
  common_internal::StructValueVariant variant_;
345
};
346
347
0
inline std::ostream& operator<<(std::ostream& out, const StructValue& value) {
348
0
  return out << value.DebugString();
349
0
}
350
351
template <>
352
struct NativeTypeTraits<StructValue> final {
353
0
  static NativeTypeId Id(const StructValue& value) { return value.GetTypeId(); }
354
};
355
356
class StructValueBuilder {
357
 public:
358
0
  virtual ~StructValueBuilder() = default;
359
360
  virtual absl::StatusOr<absl::optional<ErrorValue>> SetFieldByName(
361
      absl::string_view name, Value value) = 0;
362
363
  virtual absl::StatusOr<absl::optional<ErrorValue>> SetFieldByNumber(
364
      int64_t number, Value value) = 0;
365
366
  virtual absl::StatusOr<StructValue> Build() && = 0;
367
};
368
369
using StructValueBuilderPtr = std::unique_ptr<StructValueBuilder>;
370
371
}  // namespace cel
372
373
#endif  // THIRD_PARTY_CEL_CPP_COMMON_VALUES_STRUCT_VALUE_H_