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/optional_value.cc
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
#include <cstdint>
16
#include <string>
17
#include <utility>
18
19
#include "absl/base/attributes.h"
20
#include "absl/base/casts.h"
21
#include "absl/base/nullability.h"
22
#include "absl/log/absl_check.h"
23
#include "absl/status/status.h"
24
#include "absl/strings/str_cat.h"
25
#include "absl/strings/string_view.h"
26
#include "absl/time/time.h"
27
#include "common/arena.h"
28
#include "common/native_type.h"
29
#include "common/type.h"
30
#include "common/value.h"
31
#include "common/value_kind.h"
32
#include "google/protobuf/arena.h"
33
#include "google/protobuf/descriptor.h"
34
#include "google/protobuf/message.h"
35
36
namespace cel {
37
38
namespace {
39
40
struct OptionalValueDispatcher : public OpaqueValueDispatcher {
41
  using HasValue =
42
      bool (*)(const OptionalValueDispatcher* absl_nonnull dispatcher,
43
               CustomValueContent content);
44
  using Value = void (*)(const OptionalValueDispatcher* absl_nonnull dispatcher,
45
                         CustomValueContent content,
46
                         cel::Value* absl_nonnull result);
47
48
  absl_nonnull HasValue has_value;
49
50
  absl_nonnull Value value;
51
};
52
53
NativeTypeId OptionalValueGetTypeId(const OpaqueValueDispatcher* absl_nonnull,
54
0
                                    OpaqueValueContent) {
55
0
  return NativeTypeId::For<OptionalValue>();
56
0
}
57
58
absl::string_view OptionalValueGetTypeName(
59
0
    const OpaqueValueDispatcher* absl_nonnull, OpaqueValueContent) {
60
0
  return "optional_type";
61
0
}
62
63
OpaqueType OptionalValueGetRuntimeType(
64
0
    const OpaqueValueDispatcher* absl_nonnull, OpaqueValueContent) {
65
0
  return OptionalType();
66
0
}
67
68
std::string OptionalValueDebugString(
69
    const OpaqueValueDispatcher* absl_nonnull dispatcher,
70
0
    OpaqueValueContent content) {
71
0
  if (!static_cast<const OptionalValueDispatcher*>(dispatcher)
72
0
           ->has_value(static_cast<const OptionalValueDispatcher*>(dispatcher),
73
0
                       content)) {
74
0
    return "optional.none()";
75
0
  }
76
0
  Value value;
77
0
  static_cast<const OptionalValueDispatcher*>(dispatcher)
78
0
      ->value(static_cast<const OptionalValueDispatcher*>(dispatcher), content,
79
0
              &value);
80
0
  return absl::StrCat("optional.of(", value.DebugString(), ")");
81
0
}
82
83
bool OptionalValueHasValue(const OptionalValueDispatcher* absl_nonnull,
84
0
                           OpaqueValueContent) {
85
0
  return true;
86
0
}
87
88
absl::Status OptionalValueEqual(
89
    const OpaqueValueDispatcher* absl_nonnull dispatcher,
90
    OpaqueValueContent content, const OpaqueValue& other,
91
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
92
    google::protobuf::MessageFactory* absl_nonnull message_factory,
93
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) {
94
0
  ABSL_DCHECK(descriptor_pool != nullptr);
95
0
  ABSL_DCHECK(message_factory != nullptr);
96
0
  ABSL_DCHECK(arena != nullptr);
97
0
  ABSL_DCHECK(result != nullptr);
98
0
  if (auto other_optional = other.AsOptional(); other_optional) {
99
0
    const bool lhs_has_value =
100
0
        static_cast<const OptionalValueDispatcher*>(dispatcher)
101
0
            ->has_value(static_cast<const OptionalValueDispatcher*>(dispatcher),
102
0
                        content);
103
0
    const bool rhs_has_value = other_optional->HasValue();
104
0
    if (lhs_has_value != rhs_has_value) {
105
0
      *result = FalseValue();
106
0
      return absl::OkStatus();
107
0
    }
108
0
    if (!lhs_has_value) {
109
0
      *result = TrueValue();
110
0
      return absl::OkStatus();
111
0
    }
112
0
    Value lhs_value;
113
0
    Value rhs_value;
114
0
    static_cast<const OptionalValueDispatcher*>(dispatcher)
115
0
        ->value(static_cast<const OptionalValueDispatcher*>(dispatcher),
116
0
                content, &lhs_value);
117
0
    other_optional->Value(&rhs_value);
118
0
    return lhs_value.Equal(rhs_value, descriptor_pool, message_factory, arena,
119
0
                           result);
120
0
  }
121
0
  *result = FalseValue();
122
0
  return absl::OkStatus();
123
0
}
124
125
google::protobuf::Arena* absl_nullable OptionalValueGetArenaNull(
126
0
    const OpaqueValueDispatcher* absl_nonnull, OpaqueValueContent) {
127
0
  return nullptr;
128
0
}
129
130
OpaqueValue OptionalValueClone(
131
    const OpaqueValueDispatcher* absl_nonnull dispatcher,
132
0
    OpaqueValueContent content, google::protobuf::Arena* absl_nonnull arena) {
133
0
  return common_internal::MakeOptionalValue(dispatcher, content);
134
0
}
135
136
bool OptionalValueHasNoValue(const OptionalValueDispatcher* absl_nonnull,
137
0
                             CustomValueContent content) {
138
0
  return false;
139
0
}
140
141
void EmptyOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
142
                             CustomValueContent content,
143
0
                             cel::Value* absl_nonnull result) {
144
0
  *result =
145
0
      ErrorValue(absl::FailedPreconditionError("optional.none() dereference"));
146
0
}
147
148
void NullOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
149
                            CustomValueContent content,
150
0
                            cel::Value* absl_nonnull result) {
151
0
  *result = NullValue();
152
0
}
153
154
void BoolOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
155
                            CustomValueContent content,
156
0
                            cel::Value* absl_nonnull result) {
157
0
  *result = BoolValue(content.To<bool>());
158
0
}
159
160
void IntOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
161
                           CustomValueContent content,
162
0
                           cel::Value* absl_nonnull result) {
163
0
  *result = IntValue(content.To<int64_t>());
164
0
}
165
166
void UintOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
167
                            CustomValueContent content,
168
0
                            cel::Value* absl_nonnull result) {
169
0
  *result = UintValue(content.To<uint64_t>());
170
0
}
171
172
void DoubleOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
173
                              CustomValueContent content,
174
0
                              cel::Value* absl_nonnull result) {
175
0
  *result = DoubleValue(content.To<double>());
176
0
}
177
178
void DurationOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
179
                                CustomValueContent content,
180
0
                                cel::Value* absl_nonnull result) {
181
0
  *result = UnsafeDurationValue(content.To<absl::Duration>());
182
0
}
183
184
void TimestampOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
185
                                 CustomValueContent content,
186
0
                                 cel::Value* absl_nonnull result) {
187
0
  *result = UnsafeTimestampValue(content.To<absl::Time>());
188
0
}
189
190
ABSL_CONST_INIT const OptionalValueDispatcher
191
    empty_optional_value_dispatcher = {
192
        {
193
            .get_type_id = &OptionalValueGetTypeId,
194
            .get_arena = &OptionalValueGetArenaNull,
195
            .get_type_name = &OptionalValueGetTypeName,
196
            .debug_string = &OptionalValueDebugString,
197
            .get_runtime_type = &OptionalValueGetRuntimeType,
198
            .equal = &OptionalValueEqual,
199
            .clone = &OptionalValueClone,
200
        },
201
        &OptionalValueHasNoValue,
202
        &EmptyOptionalValueValue,
203
};
204
205
ABSL_CONST_INIT const OptionalValueDispatcher null_optional_value_dispatcher = {
206
    {
207
        .get_type_id = &OptionalValueGetTypeId,
208
        .get_arena = &OptionalValueGetArenaNull,
209
        .get_type_name = &OptionalValueGetTypeName,
210
        .debug_string = &OptionalValueDebugString,
211
        .get_runtime_type = &OptionalValueGetRuntimeType,
212
        .equal = &OptionalValueEqual,
213
        .clone = &OptionalValueClone,
214
    },
215
    &OptionalValueHasValue,
216
    &NullOptionalValueValue,
217
};
218
219
ABSL_CONST_INIT const OptionalValueDispatcher bool_optional_value_dispatcher = {
220
    {
221
        .get_type_id = &OptionalValueGetTypeId,
222
        .get_arena = &OptionalValueGetArenaNull,
223
        .get_type_name = &OptionalValueGetTypeName,
224
        .debug_string = &OptionalValueDebugString,
225
        .get_runtime_type = &OptionalValueGetRuntimeType,
226
        .equal = &OptionalValueEqual,
227
        .clone = &OptionalValueClone,
228
    },
229
    &OptionalValueHasValue,
230
    &BoolOptionalValueValue,
231
};
232
233
ABSL_CONST_INIT const OptionalValueDispatcher int_optional_value_dispatcher = {
234
    {
235
        .get_type_id = &OptionalValueGetTypeId,
236
        .get_arena = &OptionalValueGetArenaNull,
237
        .get_type_name = &OptionalValueGetTypeName,
238
        .debug_string = &OptionalValueDebugString,
239
        .get_runtime_type = &OptionalValueGetRuntimeType,
240
        .equal = &OptionalValueEqual,
241
        .clone = &OptionalValueClone,
242
    },
243
    &OptionalValueHasValue,
244
    &IntOptionalValueValue,
245
};
246
247
ABSL_CONST_INIT const OptionalValueDispatcher uint_optional_value_dispatcher = {
248
    {
249
        .get_type_id = &OptionalValueGetTypeId,
250
        .get_arena = &OptionalValueGetArenaNull,
251
        .get_type_name = &OptionalValueGetTypeName,
252
        .debug_string = &OptionalValueDebugString,
253
        .get_runtime_type = &OptionalValueGetRuntimeType,
254
        .equal = &OptionalValueEqual,
255
        .clone = &OptionalValueClone,
256
    },
257
    &OptionalValueHasValue,
258
    &UintOptionalValueValue,
259
};
260
261
ABSL_CONST_INIT const OptionalValueDispatcher
262
    double_optional_value_dispatcher = {
263
        {
264
            .get_type_id = &OptionalValueGetTypeId,
265
            .get_arena = &OptionalValueGetArenaNull,
266
            .get_type_name = &OptionalValueGetTypeName,
267
            .debug_string = &OptionalValueDebugString,
268
            .get_runtime_type = &OptionalValueGetRuntimeType,
269
            .equal = &OptionalValueEqual,
270
            .clone = &OptionalValueClone,
271
        },
272
        &OptionalValueHasValue,
273
        &DoubleOptionalValueValue,
274
};
275
276
ABSL_CONST_INIT const OptionalValueDispatcher
277
    duration_optional_value_dispatcher = {
278
        {
279
            .get_type_id = &OptionalValueGetTypeId,
280
            .get_arena = &OptionalValueGetArenaNull,
281
            .get_type_name = &OptionalValueGetTypeName,
282
            .debug_string = &OptionalValueDebugString,
283
            .get_runtime_type = &OptionalValueGetRuntimeType,
284
            .equal = &OptionalValueEqual,
285
            .clone = &OptionalValueClone,
286
        },
287
        &OptionalValueHasValue,
288
        &DurationOptionalValueValue,
289
};
290
291
ABSL_CONST_INIT const OptionalValueDispatcher
292
    timestamp_optional_value_dispatcher = {
293
        {
294
            .get_type_id = &OptionalValueGetTypeId,
295
            .get_arena = &OptionalValueGetArenaNull,
296
            .get_type_name = &OptionalValueGetTypeName,
297
            .debug_string = &OptionalValueDebugString,
298
            .get_runtime_type = &OptionalValueGetRuntimeType,
299
            .equal = &OptionalValueEqual,
300
            .clone = &OptionalValueClone,
301
        },
302
        &OptionalValueHasValue,
303
        &TimestampOptionalValueValue,
304
};
305
306
struct OptionalValueContent {
307
  const Value* absl_nonnull value;
308
  google::protobuf::Arena* absl_nonnull arena;
309
};
310
311
google::protobuf::Arena* absl_nullable GenericOptionalValueGetArena(
312
0
    const OpaqueValueDispatcher* absl_nonnull, OpaqueValueContent content) {
313
0
  return content.To<OptionalValueContent>().arena;
314
0
}
315
316
OpaqueValue GenericOptionalValueClone(
317
    const OpaqueValueDispatcher* absl_nonnull dispatcher,
318
    OpaqueValueContent content, google::protobuf::Arena* absl_nonnull arena);
319
320
void GenericOptionalValueValue(const OptionalValueDispatcher* absl_nonnull,
321
                               CustomValueContent content,
322
0
                               cel::Value* absl_nonnull result) {
323
0
  *result = *content.To<OptionalValueContent>().value;
324
0
}
325
326
ABSL_CONST_INIT const OptionalValueDispatcher optional_value_dispatcher = {
327
    {
328
        .get_type_id = &OptionalValueGetTypeId,
329
        .get_arena = &GenericOptionalValueGetArena,
330
        .get_type_name = &OptionalValueGetTypeName,
331
        .debug_string = &OptionalValueDebugString,
332
        .get_runtime_type = &OptionalValueGetRuntimeType,
333
        .equal = &OptionalValueEqual,
334
        .clone = &GenericOptionalValueClone,
335
    },
336
    &OptionalValueHasValue,
337
    &GenericOptionalValueValue,
338
};
339
340
OpaqueValue GenericOptionalValueClone(
341
    const OpaqueValueDispatcher* absl_nonnull dispatcher,
342
0
    OpaqueValueContent content, google::protobuf::Arena* absl_nonnull arena) {
343
0
  ABSL_DCHECK(arena != nullptr);
344
345
0
  cel::Value* absl_nonnull result =
346
0
      ::new (arena->AllocateAligned(sizeof(cel::Value), alignof(cel::Value)))
347
0
          cel::Value(content.To<OptionalValueContent>().value->Clone(arena));
348
0
  if (!ArenaTraits<>::trivially_destructible(result)) {
349
0
    arena->OwnDestructor(result);
350
0
  }
351
0
  return common_internal::MakeOptionalValue(
352
0
      &optional_value_dispatcher, OpaqueValueContent::From(OptionalValueContent{
353
0
                                      .value = result, .arena = arena}));
354
0
}
355
356
}  // namespace
357
358
OptionalValue OptionalValue::Of(cel::Value value,
359
0
                                google::protobuf::Arena* absl_nonnull arena) {
360
0
  ABSL_DCHECK(value.kind() != ValueKind::kError &&
361
0
              value.kind() != ValueKind::kUnknown);
362
0
  ABSL_DCHECK(arena != nullptr);
363
364
  // We can actually fit a lot more of the underlying values, avoiding arena
365
  // allocations and destructors. For now, we just do scalars.
366
0
  switch (value.kind()) {
367
0
    case ValueKind::kNull:
368
0
      return OptionalValue(&null_optional_value_dispatcher,
369
0
                           OpaqueValueContent::Zero());
370
0
    case ValueKind::kBool:
371
0
      return OptionalValue(
372
0
          &bool_optional_value_dispatcher,
373
0
          OpaqueValueContent::From(absl::implicit_cast<bool>(value.GetBool())));
374
0
    case ValueKind::kInt:
375
0
      return OptionalValue(&int_optional_value_dispatcher,
376
0
                           OpaqueValueContent::From(
377
0
                               absl::implicit_cast<int64_t>(value.GetInt())));
378
0
    case ValueKind::kUint:
379
0
      return OptionalValue(&uint_optional_value_dispatcher,
380
0
                           OpaqueValueContent::From(
381
0
                               absl::implicit_cast<uint64_t>(value.GetUint())));
382
0
    case ValueKind::kDouble:
383
0
      return OptionalValue(&double_optional_value_dispatcher,
384
0
                           OpaqueValueContent::From(
385
0
                               absl::implicit_cast<double>(value.GetDouble())));
386
0
    case ValueKind::kDuration:
387
0
      return OptionalValue(
388
0
          &duration_optional_value_dispatcher,
389
0
          OpaqueValueContent::From(value.GetDuration().ToDuration()));
390
0
    case ValueKind::kTimestamp:
391
0
      return OptionalValue(
392
0
          &timestamp_optional_value_dispatcher,
393
0
          OpaqueValueContent::From(value.GetTimestamp().ToTime()));
394
0
    default: {
395
0
      cel::Value* absl_nonnull result = ::new (
396
0
          arena->AllocateAligned(sizeof(cel::Value), alignof(cel::Value)))
397
0
          cel::Value(std::move(value));
398
0
      if (!ArenaTraits<>::trivially_destructible(result)) {
399
0
        arena->OwnDestructor(result);
400
0
      }
401
0
      return OptionalValue(&optional_value_dispatcher,
402
0
                           OpaqueValueContent::From(OptionalValueContent{
403
0
                               .value = result, .arena = arena}));
404
0
    }
405
0
  }
406
0
}
407
408
0
OptionalValue OptionalValue::None() {
409
0
  return OptionalValue(&empty_optional_value_dispatcher,
410
0
                       OpaqueValueContent::Zero());
411
0
}
412
413
0
bool OptionalValue::HasValue() const {
414
0
  return static_cast<const OptionalValueDispatcher*>(OpaqueValue::dispatcher())
415
0
      ->has_value(static_cast<const OptionalValueDispatcher*>(
416
0
                      OpaqueValue::dispatcher()),
417
0
                  OpaqueValue::content());
418
0
}
419
420
0
void OptionalValue::Value(cel::Value* absl_nonnull result) const {
421
0
  ABSL_DCHECK(result != nullptr);
422
423
0
  static_cast<const OptionalValueDispatcher*>(OpaqueValue::dispatcher())
424
0
      ->value(static_cast<const OptionalValueDispatcher*>(
425
0
                  OpaqueValue::dispatcher()),
426
0
              OpaqueValue::content(), result);
427
0
}
428
429
0
cel::Value OptionalValue::Value() const {
430
0
  cel::Value result;
431
0
  Value(&result);
432
0
  return result;
433
0
}
434
435
}  // namespace cel