Coverage Report

Created: 2026-10-09 06:57

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