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