/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_ |