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