blob: 2903ceaa10d546b941bdc700a444384f5a895f3e [file] [log] [blame]
Jiyong Parkab7dc5a2019-05-31 03:43:34 +09001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jiyong Parkf7bb3e82021-12-10 22:46:25 +090017// Result<T, E> is the type that is used to pass a success value of type T or an error code of type
18// E, optionally together with an error message. T and E can be any type. If E is omitted it
19// defaults to int, which is useful when errno(3) is used as the error code.
Jiyong Parkab7dc5a2019-05-31 03:43:34 +090020//
Jiyong Parkf7bb3e82021-12-10 22:46:25 +090021// Passing a success value or an error value:
Jiyong Parkab7dc5a2019-05-31 03:43:34 +090022//
Jiyong Parkf7bb3e82021-12-10 22:46:25 +090023// Result<std::string> readFile() {
24// std::string content;
25// if (base::ReadFileToString("path", &content)) {
26// return content; // ok case
27// } else {
28// return ErrnoError() << "failed to read"; // error case
Jiyong Parkab7dc5a2019-05-31 03:43:34 +090029// }
Jiyong Parkab7dc5a2019-05-31 03:43:34 +090030// }
31//
Jiyong Parkf7bb3e82021-12-10 22:46:25 +090032// Checking the result and then unwrapping the value or propagating the error:
33//
34// Result<bool> hasAWord() {
35// auto content = readFile();
36// if (!content.ok()) {
37// return Error() << "failed to process: " << content.error();
38// }
39// return (*content.find("happy") != std::string::npos);
40// }
41//
42// Using custom error code type:
43//
Jiyong Park7706f492021-12-14 22:33:38 +090044// enum class MyError { A, B }; // assume that this is the error code you already have
45//
46// // To use the error code with Result, define a wrapper class that provides the following
47// operations and use the wrapper class as the second type parameter (E) when instantiating
48// Result<T, E>
49//
50// 1. default constructor
51// 2. copy constructor / and move constructor if copying is expensive
52// 3. conversion operator to the error code type
53// 4. value() function that return the error code value
54// 5. print() function that gives a string representation of the error ode value
55//
56// struct MyErrorWrapper {
57// MyError val_;
58// MyErrorWrapper() : val_(/* reasonable default value */) {}
59// MyErrorWrapper(MyError&& e) : val_(std:forward<MyError>(e)) {}
60// operator const MyError&() const { return val_; }
61// MyError value() const { return val_; }
62// std::string print() const {
63// switch(val_) {
Jiyong Parkf7bb3e82021-12-10 22:46:25 +090064// MyError::A: return "A";
65// MyError::B: return "B";
66// }
67// }
68// };
69//
Jiyong Park7706f492021-12-14 22:33:38 +090070// #define NewMyError(e) Error<MyErrorWrapper>(MyError::e)
Jiyong Parkf7bb3e82021-12-10 22:46:25 +090071//
72// Result<T, MyError> val = NewMyError(A) << "some message";
73//
74// Formatting the error message using fmtlib:
75//
76// Errorf("{} errors", num); // equivalent to Error() << num << " errors";
77// ErrnoErrorf("{} errors", num); // equivalent to ErrnoError() << num << " errors";
78//
79// Returning success or failure, but not the value:
80//
81// Result<void> doSomething() {
82// if (success) return {};
83// else return Error() << "error occurred";
84// }
85//
86// Extracting error code:
87//
88// Result<T> val = Error(3) << "some error occurred";
89// assert(3 == val.error().code());
90//
Jiyong Parkab7dc5a2019-05-31 03:43:34 +090091
92#pragma once
93
Jiyong Parkf7bb3e82021-12-10 22:46:25 +090094#include <assert.h>
Jiyong Parkab7dc5a2019-05-31 03:43:34 +090095#include <errno.h>
96
97#include <sstream>
98#include <string>
Atneya Nair6a6a7e52022-02-11 18:18:23 -050099#include <type_traits>
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900100
Jiyong Park7706f492021-12-14 22:33:38 +0900101#include "android-base/errors.h"
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900102#include "android-base/expected.h"
Tom Cherry377d1ad2019-06-14 14:34:54 -0700103#include "android-base/format.h"
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900104
105namespace android {
106namespace base {
107
Jiyong Park7706f492021-12-14 22:33:38 +0900108// Errno is a wrapper class for errno(3). Use this type instead of `int` when instantiating
109// `Result<T, E>` and `Error<E>` template classes. This is required to distinguish errno from other
110// integer-based error code types like `status_t`.
111struct Errno {
112 Errno() : val_(0) {}
113 Errno(int e) : val_(e) {}
114 int value() const { return val_; }
115 operator int() const { return value(); }
116 std::string print() const { return strerror(value()); }
117
118 int val_;
119
120 // TODO(b/209929099): remove this conversion operator. This currently is needed to not break
121 // existing places where error().code() is used to construct enum values.
122 template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>>
123 operator E() const {
124 return E(val_);
125 }
126};
127
Jiyong Park959593a2022-01-03 17:43:12 +0900128template <typename E = Errno, bool include_message = true>
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900129struct ResultError {
Jiyong Park7706f492021-12-14 22:33:38 +0900130 template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>>
131 ResultError(T&& message, P&& code)
132 : message_(std::forward<T>(message)), code_(E(std::forward<P>(code))) {}
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900133
134 template <typename T>
Maciej Żenczykowskib39ecb42020-01-26 20:12:30 -0800135 // NOLINTNEXTLINE(google-explicit-constructor)
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900136 operator android::base::expected<T, ResultError<E>>() const {
137 return android::base::unexpected(ResultError<E>(message_, code_));
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900138 }
139
140 std::string message() const { return message_; }
Jiyong Park7706f492021-12-14 22:33:38 +0900141 const E& code() const { return code_; }
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900142
143 private:
144 std::string message_;
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900145 E code_;
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900146};
147
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900148template <typename E>
Jiyong Park959593a2022-01-03 17:43:12 +0900149struct ResultError<E, /* include_message */ false> {
150 template <typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>>
151 ResultError(P&& code) : code_(E(std::forward<P>(code))) {}
152
153 template <typename T>
154 operator android::base::expected<T, ResultError<E, false>>() const {
155 return android::base::unexpected(ResultError<E, false>(code_));
156 }
157
158 const E& code() const { return code_; }
159
160 private:
161 E code_;
162};
163
164template <typename E>
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900165inline bool operator==(const ResultError<E>& lhs, const ResultError<E>& rhs) {
Jiyong Parkbdf42dc2019-06-05 18:33:01 +0900166 return lhs.message() == rhs.message() && lhs.code() == rhs.code();
167}
168
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900169template <typename E>
170inline bool operator!=(const ResultError<E>& lhs, const ResultError<E>& rhs) {
Jiyong Parkbdf42dc2019-06-05 18:33:01 +0900171 return !(lhs == rhs);
172}
173
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900174template <typename E>
175inline std::ostream& operator<<(std::ostream& os, const ResultError<E>& t) {
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900176 os << t.message();
177 return os;
178}
179
Jiyong Park959593a2022-01-03 17:43:12 +0900180namespace internal {
181// Stream class that does nothing and is has zero (actually 1) size. It is used instead of
182// std::stringstream when include_message is false so that we use less on stack.
183// sizeof(std::stringstream) is 280 on arm64.
184struct DoNothingStream {
185 template <typename T>
186 DoNothingStream& operator<<(T&&) {
187 return *this;
188 }
189
190 std::string str() const { return ""; }
191};
192} // namespace internal
193
194template <typename E = Errno, bool include_message = true,
195 typename = std::enable_if_t<!std::is_same_v<E, int>>>
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900196class Error {
197 public:
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900198 Error() : code_(0), has_code_(false) {}
Jiyong Park7706f492021-12-14 22:33:38 +0900199 template <typename P, typename = std::enable_if_t<std::is_convertible_v<P, E>>>
Maciej Żenczykowskib39ecb42020-01-26 20:12:30 -0800200 // NOLINTNEXTLINE(google-explicit-constructor)
Jiyong Park7706f492021-12-14 22:33:38 +0900201 Error(P&& code) : code_(std::forward<P>(code)), has_code_(true) {}
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900202
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900203 template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<E, P>>>
Maciej Żenczykowskib39ecb42020-01-26 20:12:30 -0800204 // NOLINTNEXTLINE(google-explicit-constructor)
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900205 operator android::base::expected<T, ResultError<P>>() const {
206 return android::base::unexpected(ResultError<P>(str(), static_cast<P>(code_)));
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900207 }
208
Jiyong Park959593a2022-01-03 17:43:12 +0900209 template <typename T, typename P, typename = std::enable_if_t<std::is_convertible_v<E, P>>>
210 // NOLINTNEXTLINE(google-explicit-constructor)
211 operator android::base::expected<T, ResultError<P, false>>() const {
212 return android::base::unexpected(ResultError<P, false>(static_cast<P>(code_)));
213 }
214
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900215 template <typename T>
216 Error& operator<<(T&& t) {
Jiyong Park959593a2022-01-03 17:43:12 +0900217 static_assert(include_message, "<< not supported when include_message = false");
Maciej Żenczykowskice99a912020-04-24 11:21:21 -0700218 // NOLINTNEXTLINE(bugprone-suspicious-semicolon)
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900219 if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError<E>>) {
220 if (!has_code_) {
221 code_ = t.code();
222 }
Jooyung Han072c7142019-06-11 13:38:01 +0900223 return (*this) << t.message();
224 }
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900225 int saved = errno;
226 ss_ << t;
227 errno = saved;
228 return *this;
229 }
230
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900231 const std::string str() const {
Jiyong Park959593a2022-01-03 17:43:12 +0900232 static_assert(include_message, "str() not supported when include_message = false");
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900233 std::string str = ss_.str();
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900234 if (has_code_) {
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900235 if (str.empty()) {
Jiyong Park7706f492021-12-14 22:33:38 +0900236 return code_.print();
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900237 }
Jiyong Park7706f492021-12-14 22:33:38 +0900238 return std::move(str) + ": " + code_.print();
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900239 }
240 return str;
241 }
242
243 Error(const Error&) = delete;
244 Error(Error&&) = delete;
245 Error& operator=(const Error&) = delete;
246 Error& operator=(Error&&) = delete;
247
Tom Cherry81f5f502020-02-04 15:18:29 -0800248 template <typename T, typename... Args>
249 friend Error ErrorfImpl(const T&& fmt, const Args&... args);
Jiyong Park4e223e62019-06-12 16:25:04 +0900250
Tom Cherry81f5f502020-02-04 15:18:29 -0800251 template <typename T, typename... Args>
252 friend Error ErrnoErrorfImpl(const T&& fmt, const Args&... args);
Jiyong Park4e223e62019-06-12 16:25:04 +0900253
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900254 private:
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900255 Error(bool has_code, E code, const std::string& message) : code_(code), has_code_(has_code) {
Jiyong Park4e223e62019-06-12 16:25:04 +0900256 (*this) << message;
257 }
258
Jiyong Park959593a2022-01-03 17:43:12 +0900259 std::conditional_t<include_message, std::stringstream, internal::DoNothingStream> ss_;
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900260 E code_;
261 const bool has_code_;
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900262};
263
Jiyong Park7706f492021-12-14 22:33:38 +0900264inline Error<Errno> ErrnoError() {
265 return Error<Errno>(Errno{errno});
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900266}
267
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900268template <typename E>
269inline E ErrorCode(E code) {
Jiyong Park4e223e62019-06-12 16:25:04 +0900270 return code;
271}
272
273// Return the error code of the last ResultError object, if any.
274// Otherwise, return `code` as it is.
Jiyong Parkf7bb3e82021-12-10 22:46:25 +0900275template <typename T, typename E, typename... Args>
276inline E ErrorCode(E code, T&& t, const Args&... args) {
277 if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, ResultError<E>>) {
Jiyong Park4e223e62019-06-12 16:25:04 +0900278 return ErrorCode(t.code(), args...);
279 }
280 return ErrorCode(code, args...);
281}
282
Tom Cherry81f5f502020-02-04 15:18:29 -0800283template <typename T, typename... Args>
Jiyong Park7706f492021-12-14 22:33:38 +0900284inline Error<Errno> ErrorfImpl(const T&& fmt, const Args&... args) {
285 return Error(false, ErrorCode(Errno{}, args...), fmt::format(fmt, args...));
Jiyong Park4e223e62019-06-12 16:25:04 +0900286}
287
Tom Cherry81f5f502020-02-04 15:18:29 -0800288template <typename T, typename... Args>
Jiyong Park7706f492021-12-14 22:33:38 +0900289inline Error<Errno> ErrnoErrorfImpl(const T&& fmt, const Args&... args) {
290 return Error<Errno>(true, Errno{errno}, fmt::format(fmt, args...));
Jiyong Park4e223e62019-06-12 16:25:04 +0900291}
292
Tom Cherry81f5f502020-02-04 15:18:29 -0800293#define Errorf(fmt, ...) android::base::ErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
294#define ErrnoErrorf(fmt, ...) android::base::ErrnoErrorfImpl(FMT_STRING(fmt), ##__VA_ARGS__)
295
Jiyong Park959593a2022-01-03 17:43:12 +0900296template <typename T, typename E = Errno, bool include_message = true>
297using Result = android::base::expected<T, ResultError<E, include_message>>;
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900298
Jiyong Park7706f492021-12-14 22:33:38 +0900299// Specialization of android::base::OkOrFail<V> for V = Result<T, E>. See android-base/errors.h
300// for the contract.
Atneya Nair6a6a7e52022-02-11 18:18:23 -0500301
302namespace impl {
303template <typename U>
304using Code = std::decay_t<decltype(std::declval<U>().error().code())>;
305
306template <typename U>
307using ErrorType = std::decay_t<decltype(std::declval<U>().error())>;
308
309template <typename U>
310constexpr bool IsNumeric = std::is_integral_v<U> || std::is_floating_point_v<U> ||
311 (std::is_enum_v<U> && std::is_convertible_v<U, size_t>);
312
313// This base class exists to take advantage of shadowing
314// We include the conversion in this base class so that if the conversion in NumericConversions
315// overlaps, we (arbitrarily) choose the implementation in NumericConversions due to shadowing.
316template <typename T>
317struct ConversionBase {
318 ErrorType<T> error_;
319 // T is a expected<U, ErrorType<T>>.
320 operator const T() const && {
321 return unexpected(std::move(error_));
322 }
323
324 operator const Code<T>() const && {
325 return error_.code();
326 }
327
328};
329
330// User defined conversions can be followed by numeric conversions
331// Although we template specialize for the exact code type, we need
332// specializations for conversions to all numeric types to avoid an
333// ambiguous conversion sequence.
334template <typename T, typename = void>
335struct NumericConversions : public ConversionBase<T> {};
336template <typename T>
337struct NumericConversions<T,
338 std::enable_if_t<impl::IsNumeric<impl::Code<T>>>
339 > : public ConversionBase<T>
340{
341#pragma push_macro("SPECIALIZED_CONVERSION")
342#define SPECIALIZED_CONVERSION(type)\
343 operator const expected<type, ErrorType<T>>() const &&\
344 { return unexpected(std::move(this->error_));}
345
346 SPECIALIZED_CONVERSION(int)
347 SPECIALIZED_CONVERSION(short int)
348 SPECIALIZED_CONVERSION(unsigned short int)
349 SPECIALIZED_CONVERSION(unsigned int)
350 SPECIALIZED_CONVERSION(long int)
351 SPECIALIZED_CONVERSION(unsigned long int)
352 SPECIALIZED_CONVERSION(long long int)
353 SPECIALIZED_CONVERSION(unsigned long long int)
354 SPECIALIZED_CONVERSION(bool)
355 SPECIALIZED_CONVERSION(char)
356 SPECIALIZED_CONVERSION(unsigned char)
357 SPECIALIZED_CONVERSION(signed char)
358 SPECIALIZED_CONVERSION(wchar_t)
359 SPECIALIZED_CONVERSION(char16_t)
360 SPECIALIZED_CONVERSION(char32_t)
361 SPECIALIZED_CONVERSION(float)
362 SPECIALIZED_CONVERSION(double)
363 SPECIALIZED_CONVERSION(long double)
364
365#undef SPECIALIZED_CONVERSION
366#pragma pop_macro("SPECIALIZED_CONVERSION")
367 // For debugging purposes
368 using IsNumericT = std::true_type;
369};
370
371#ifdef __cpp_concepts
372template<class U>
373concept Trivial = std::is_same_v<U, U>;
374#endif
375} // namespace impl
376
377template <typename T, typename E, bool include_message>
378struct OkOrFail<Result<T, E, include_message>>
379 : public impl::NumericConversions<Result<T, E, include_message>> {
380 using V = Result<T, E, include_message>;
381 using Err = impl::ErrorType<V>;
382 using C = impl::Code<V>;
383private:
384 OkOrFail(Err&& v): impl::NumericConversions<V>{std::move(v)} {}
385 OkOrFail(const OkOrFail& other) = delete;
386 OkOrFail(const OkOrFail&& other) = delete;
387public:
Jiyong Park7706f492021-12-14 22:33:38 +0900388 // Checks if V is ok or fail
389 static bool IsOk(const V& val) { return val.ok(); }
390
391 // Turns V into a success value
Jiakai Zhang9f1f5ff2022-06-06 19:42:48 +0100392 static T Unwrap(V&& val) {
393 if constexpr (std::is_same_v<T, void>) {
394 assert(IsOk(val));
395 return;
396 } else {
397 return std::move(val.value());
398 }
399 }
Jiyong Park7706f492021-12-14 22:33:38 +0900400
401 // Consumes V when it's a fail value
Atneya Nair6a6a7e52022-02-11 18:18:23 -0500402 static const OkOrFail<V> Fail(V&& v) {
Jiyong Park7706f492021-12-14 22:33:38 +0900403 assert(!IsOk(v));
Atneya Nair6a6a7e52022-02-11 18:18:23 -0500404 return OkOrFail<V>{std::move(v.error())};
Jiyong Park7706f492021-12-14 22:33:38 +0900405 }
Jiyong Park7706f492021-12-14 22:33:38 +0900406
Atneya Nair6a6a7e52022-02-11 18:18:23 -0500407 // We specialize as much as possible to avoid ambiguous conversion with
408 // templated expected ctor
409 operator const Result<C, E, include_message>() const && {
410 return unexpected(std::move(this->error_));
Jiyong Park7706f492021-12-14 22:33:38 +0900411 }
Atneya Nair6a6a7e52022-02-11 18:18:23 -0500412#ifdef __cpp_concepts
413 template <impl::Trivial U>
414#else
Jiyong Park7706f492021-12-14 22:33:38 +0900415 template <typename U>
Atneya Nair6a6a7e52022-02-11 18:18:23 -0500416#endif
417 operator const Result<U, E, include_message>() const && {
418 return unexpected(std::move(this->error_));
Jiyong Park7706f492021-12-14 22:33:38 +0900419 }
420
421 static std::string ErrorMessage(const V& val) { return val.error().message(); }
422};
423
Bernie Innocenti9cc7edc2020-02-06 02:51:42 +0900424// Macros for testing the results of functions that return android::base::Result.
425// These also work with base::android::expected.
Yifan Hongf21c5462021-05-21 18:43:16 -0700426// For advanced matchers and customized error messages, see result-gtest.h.
Bernie Innocenti9cc7edc2020-02-06 02:51:42 +0900427
Jiyong Parkc6efce12021-12-20 15:17:58 +0900428#define ASSERT_RESULT_OK(stmt) \
429 if (const auto& tmp = (stmt); !tmp.ok()) \
430 FAIL() << "Value of: " << #stmt << "\n" \
431 << " Actual: " << tmp.error().message() << "\n" \
432 << "Expected: is ok\n"
Bernie Innocenti9cc7edc2020-02-06 02:51:42 +0900433
Jiyong Parkc6efce12021-12-20 15:17:58 +0900434#define EXPECT_RESULT_OK(stmt) \
435 if (const auto& tmp = (stmt); !tmp.ok()) \
436 ADD_FAILURE() << "Value of: " << #stmt << "\n" \
437 << " Actual: " << tmp.error().message() << "\n" \
438 << "Expected: is ok\n"
Bernie Innocenti9cc7edc2020-02-06 02:51:42 +0900439
Jiyong Parkab7dc5a2019-05-31 03:43:34 +0900440} // namespace base
441} // namespace android