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/error_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
#ifndef THIRD_PARTY_CEL_CPP_COMMON_VALUES_ERROR_VALUE_H_
19
#define THIRD_PARTY_CEL_CPP_COMMON_VALUES_ERROR_VALUE_H_
20
21
#include <cstddef>
22
#include <memory>
23
#include <new>
24
#include <ostream>
25
#include <string>
26
#include <type_traits>
27
#include <utility>
28
29
#include "absl/base/attributes.h"
30
#include "absl/base/nullability.h"
31
#include "absl/log/absl_check.h"
32
#include "absl/status/status.h"
33
#include "absl/status/statusor.h"
34
#include "absl/strings/cord.h"
35
#include "absl/strings/string_view.h"
36
#include "common/arena.h"
37
#include "common/type.h"
38
#include "common/value_kind.h"
39
#include "common/values/values.h"
40
#include "google/protobuf/arena.h"
41
#include "google/protobuf/descriptor.h"
42
#include "google/protobuf/io/zero_copy_stream.h"
43
#include "google/protobuf/message.h"
44
45
namespace cel {
46
47
class Value;
48
49
// `ErrorValue` represents values of the `ErrorType`.
50
class ABSL_ATTRIBUTE_TRIVIAL_ABI ErrorValue final
51
    : private common_internal::ValueMixin<ErrorValue> {
52
 public:
53
  static constexpr ValueKind kKind = ValueKind::kError;
54
55
74.9k
  explicit ErrorValue(absl::Status value) : arena_(nullptr) {
56
74.9k
    ::new (static_cast<void*>(&status_.val[0])) absl::Status(std::move(value));
57
149k
    ABSL_DCHECK(*this) << "ErrorValue requires a non-OK absl::Status";
58
74.9k
  }
59
60
  // By default, this creates an UNKNOWN error. You should always create a more
61
  // specific error value.
62
  ErrorValue();
63
64
103k
  ErrorValue(const ErrorValue& other) { CopyConstruct(other); }
65
66
393k
  ErrorValue(ErrorValue&& other) noexcept { MoveConstruct(other); }
67
68
572k
  ~ErrorValue() { Destruct(); }
69
70
0
  ErrorValue& operator=(const ErrorValue& other) {
71
0
    if (this != &other) {
72
0
      Destruct();
73
0
      CopyConstruct(other);
74
0
    }
75
0
    return *this;
76
0
  }
77
78
92.3k
  ErrorValue& operator=(ErrorValue&& other) noexcept {
79
92.3k
    if (this != &other) {
80
92.3k
      Destruct();
81
92.3k
      MoveConstruct(other);
82
92.3k
    }
83
92.3k
    return *this;
84
92.3k
  }
85
86
0
  static constexpr ValueKind kind() { return kKind; }
87
88
0
  static absl::string_view GetTypeName() { return ErrorType::kName; }
89
90
  std::string DebugString() const;
91
92
  // See Value::SerializeTo().
93
  absl::Status SerializeTo(
94
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
95
      google::protobuf::MessageFactory* absl_nonnull message_factory,
96
      google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const;
97
98
  // See Value::ConvertToJson().
99
  absl::Status ConvertToJson(
100
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
101
      google::protobuf::MessageFactory* absl_nonnull message_factory,
102
      google::protobuf::Message* absl_nonnull json) const;
103
104
  absl::Status Equal(const Value& other,
105
                     const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
106
                     google::protobuf::MessageFactory* absl_nonnull message_factory,
107
                     google::protobuf::Arena* absl_nonnull arena,
108
                     Value* absl_nonnull result) const;
109
  using ValueMixin::Equal;
110
111
0
  bool IsZeroValue() const { return false; }
112
113
  ErrorValue Clone(google::protobuf::Arena* absl_nonnull arena) const;
114
115
  absl::Status ToStatus() const&;
116
117
  absl::Status ToStatus() &&;
118
119
  ABSL_DEPRECATED("Use ToStatus()")
120
5.05k
  absl::Status NativeValue() const& { return ToStatus(); }
121
122
  ABSL_DEPRECATED("Use ToStatus()")
123
0
  absl::Status NativeValue() && { return std::move(*this).ToStatus(); }
124
125
  friend void swap(ErrorValue& lhs, ErrorValue& rhs) noexcept;
126
127
  explicit operator bool() const;
128
129
 private:
130
  friend class common_internal::ValueMixin<ErrorValue>;
131
  friend struct ArenaTraits<ErrorValue>;
132
133
  ErrorValue(google::protobuf::Arena* absl_nonnull arena,
134
             const absl::Status* absl_nonnull status)
135
0
      : arena_(arena) {
136
0
    status_.ptr = status;
137
0
  }
138
139
103k
  void CopyConstruct(const ErrorValue& other) {
140
103k
    arena_ = other.arena_;
141
103k
    if (arena_ == nullptr) {
142
103k
      ::new (static_cast<void*>(&status_.val[0])) absl::Status(*std::launder(
143
103k
          reinterpret_cast<const absl::Status*>(&other.status_.val[0])));
144
103k
    } else {
145
0
      status_.ptr = other.status_.ptr;
146
0
    }
147
103k
  }
148
149
486k
  void MoveConstruct(ErrorValue& other) {
150
486k
    arena_ = other.arena_;
151
486k
    if (arena_ == nullptr) {
152
486k
      ::new (static_cast<void*>(&status_.val[0]))
153
486k
          absl::Status(std::move(*std::launder(
154
486k
              reinterpret_cast<absl::Status*>(&other.status_.val[0]))));
155
486k
    } else {
156
0
      status_.ptr = other.status_.ptr;
157
0
    }
158
486k
  }
159
160
665k
  void Destruct() {
161
665k
    if (arena_ == nullptr) {
162
665k
      std::launder(reinterpret_cast<absl::Status*>(&status_.val[0]))->~Status();
163
665k
    }
164
665k
  }
165
166
  google::protobuf::Arena* absl_nullable arena_;
167
  union {
168
    alignas(absl::Status) char val[sizeof(absl::Status)];
169
    const absl::Status* absl_nonnull ptr;
170
  } status_;
171
};
172
173
ErrorValue NoSuchFieldError(absl::string_view field);
174
175
ErrorValue NoSuchKeyError(absl::string_view key);
176
177
ErrorValue NoSuchTypeError(absl::string_view type);
178
179
ErrorValue DuplicateKeyError();
180
181
ErrorValue TypeConversionError(absl::string_view from, absl::string_view to);
182
183
ErrorValue TypeConversionError(const Type& from, const Type& to);
184
185
ErrorValue IndexOutOfBoundsError(size_t index);
186
187
ErrorValue IndexOutOfBoundsError(ptrdiff_t index);
188
189
// Catch other integrals and forward them to the above ones. This is needed to
190
// avoid ambiguous overload issues for smaller integral types like `int`.
191
template <typename T>
192
std::enable_if_t<std::conjunction_v<std::is_integral<T>, std::is_unsigned<T>,
193
                                    std::negation<std::is_same<T, size_t>>>,
194
                 ErrorValue>
195
IndexOutOfBoundsError(T index) {
196
  static_assert(sizeof(T) <= sizeof(size_t));
197
  return IndexOutOfBoundsError(static_cast<size_t>(index));
198
}
199
template <typename T>
200
std::enable_if_t<std::conjunction_v<std::is_integral<T>, std::is_signed<T>,
201
                                    std::negation<std::is_same<T, ptrdiff_t>>>,
202
                 ErrorValue>
203
0
IndexOutOfBoundsError(T index) {
204
0
  static_assert(sizeof(T) <= sizeof(ptrdiff_t));
205
0
  return IndexOutOfBoundsError(static_cast<ptrdiff_t>(index));
206
0
}
207
208
0
inline std::ostream& operator<<(std::ostream& out, const ErrorValue& value) {
209
0
  return out << value.DebugString();
210
0
}
211
212
bool IsNoSuchField(const ErrorValue& value);
213
214
bool IsNoSuchKey(const ErrorValue& value);
215
216
class ErrorValueReturn final {
217
 public:
218
  ErrorValueReturn() = default;
219
220
136
  ErrorValue operator()(absl::Status status) const {
221
136
    return ErrorValue(std::move(status));
222
136
  }
223
};
224
225
namespace common_internal {
226
227
struct ImplicitlyConvertibleStatus {
228
  // NOLINTNEXTLINE(google-explicit-constructor)
229
0
  operator absl::Status() const { return absl::OkStatus(); }
230
231
  template <typename T>
232
  // NOLINTNEXTLINE(google-explicit-constructor)
233
  operator absl::StatusOr<T>() const {
234
    return T();
235
  }
236
};
237
238
}  // namespace common_internal
239
240
// For use with `RETURN_IF_ERROR(...).With(cel::ErrorValueAssign(&result))` and
241
// `ASSIGN_OR_RETURN(..., ..., _.With(cel::ErrorValueAssign(&result)))`.
242
//
243
// IMPORTANT:
244
// If the returning type is `absl::Status` the result will be
245
// `absl::OkStatus()`. If the returning type is `absl::StatusOr<T>` the result
246
// will be `T()`.
247
class ErrorValueAssign final {
248
 public:
249
  ErrorValueAssign() = delete;
250
251
  explicit ErrorValueAssign(Value& value ABSL_ATTRIBUTE_LIFETIME_BOUND)
252
0
      : ErrorValueAssign(std::addressof(value)) {}
253
254
  explicit ErrorValueAssign(
255
      Value* absl_nonnull value ABSL_ATTRIBUTE_LIFETIME_BOUND)
256
0
      : value_(value) {
257
0
    ABSL_DCHECK(value != nullptr);
258
0
  }
259
260
  common_internal::ImplicitlyConvertibleStatus operator()(
261
      absl::Status status) const;
262
263
 private:
264
  Value* absl_nonnull value_;
265
};
266
267
template <>
268
struct ArenaTraits<ErrorValue> {
269
74.9k
  static bool trivially_destructible(const ErrorValue& value) {
270
74.9k
    return value.arena_ != nullptr;
271
74.9k
  }
272
};
273
274
}  // namespace cel
275
276
#endif  // THIRD_PARTY_CEL_CPP_COMMON_VALUES_ERROR_VALUE_H_