blob: 0ff1711b67abfaaef3e72459af5d662fb28faf1c [file] [log] [blame]
Lingfeng Yang1bb3ca42020-10-29 12:31:49 -07001// Copyright (C) 2018 The Android Open Source Project
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// http://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#pragma once
16
17#include "base/Optional.h"
18
19// Result<T, E> - a template class to store either a result or error, inspired
20// by Rust.
21//
22// T is the successful result type, and may be void.
23// E is the error result type.
24//
25// To return success, return Ok(value) or Ok().
26// To return error, return Err(value).
27//
28// Usage in APIs:
29//
30// class MyError1 { Error1, Error2 };
31// typedef Result<void, MyError> MyResult;
32//
33// MyResult function() {
34// if (good()) return Ok();
35// else return Err(MyError::Error1);
36// }
37//
38// Checking results:
39//
40// if (result.ok()) { auto value = *result.ok(); } // no error
41// return result; // propagate result as-is
42// RETURN_IF_ERR(result); // propagate error
43// switch (*result.err()) { ... } // handle error
44//
45// auto result = function();
46// RETURN_IF_ERR(result); // propagate error
47
48// Helper to propagate errors.
49#define RETURN_IF_ERR(...) \
50 do { \
51 auto&& __result = __VA_ARGS__; \
52 if (__result.err()) { \
53 return ::android::base::Err(__result.unwrapErr()); \
54 } \
55 } while (false)
56
57namespace android {
58namespace base {
59
60namespace detail {
61
62template <typename T>
63struct Ok {
64 Ok(const T& value) : value(value) {}
65 Ok(T&& value) : value(std::move(value)) {}
66
67 Ok(Ok&& other) : value(std::move(other.value)) {}
68
69 T value;
70};
71
72template <>
73struct Ok<void> {
74 Ok() = default;
75};
76
77template <typename E>
78struct Err {
79public:
80 Err(const E& value) : value(value) {}
81 Err(E&& value) : value(std::move(value)) {}
82
83 Err(Err&& other) : value(std::move(other.value)) {}
84
85 E value;
86};
87
88template <typename T, typename E>
89struct ResultStorage {
90 template <typename U,
91 typename = typename std::enable_if<
92 std::is_convertible<T, U>::value>::type>
93 ResultStorage(Ok<U>&& ok) : ok(std::move(ok.value)) {}
94
95 ResultStorage(Err<E>&& err) : err(std::move(err.value)) {}
96
97 bool isOk() const { return ok.hasValue(); }
98
99 Optional<T> ok;
100 Optional<E> err;
101};
102
103template <typename E>
104struct ResultStorage<void, E> {
105 ResultStorage(Ok<void>&& ok) {}
106 ResultStorage(Err<E>&& err) : err(std::move(err.value)) {}
107
108 bool isOk() const { return !err.hasValue(); }
109
110 Optional<E> err;
111};
112
113} // namespace detail
114
115template <typename T, typename Value = typename std::decay<T>::type>
116detail::Ok<Value> Ok(T&& value) {
117 return detail::Ok<Value>(std::forward<T>(value));
118}
119
120static inline detail::Ok<void> Ok() {
121 return detail::Ok<void>();
122}
123
124template <typename E, typename Value = typename std::decay<E>::type>
125detail::Err<Value> Err(E&& value) {
126 return detail::Err<Value>(std::forward<E>(value));
127}
128
129template <typename T, typename E>
130class Result {
131public:
132 template <typename U,
133 typename = typename std::enable_if<
134 std::is_convertible<U, T>::value>::type>
135 Result(detail::Ok<U>&& ok) : mStorage(std::move(ok)) {}
136 Result(detail::Err<E>&& err) : mStorage(std::move(err)) {}
137
138 Result(Result&& other)
139 : mStorage(std::move(other.mStorage)), mValid(other.mValid) {
140 other.mValid = false;
141 }
142
143 // Returns an Optional<T> representing the value, not defined is T is void.
144 template <typename U = T>
145 typename std::enable_if<!std::is_void<U>::value &&
146 std::is_copy_constructible<U>::value,
147 Optional<U>>::type
148 ok() {
149 CHECK(mValid) << "Result invalid";
150 return mStorage.ok;
151 }
152 template <typename U = T>
153 typename std::enable_if<!std::is_void<U>::value, const Optional<U>&>::type
154 ok() const {
155 CHECK(mValid) << "Result invalid";
156 return mStorage.ok;
157 }
158
159 // For Result<void, E> types, returns true if the Result is ok.
160 template <typename U = T>
161 typename std::enable_if<std::is_void<U>::value, bool>::type ok() const {
162 CHECK(mValid) << "Result invalid";
163 return mStorage.isOk();
164 }
165
166 // Returns an Optional<E> representing the error, if it exists.
167 template <typename U = E>
168 typename std::enable_if<std::is_copy_constructible<U>::value,
169 Optional<U>>::type
170 err() {
171 CHECK(mValid) << "Result invalid";
172 return mStorage.err;
173 }
174 const Optional<E>& err() const {
175 CHECK(mValid) << "Result invalid";
176 return mStorage.err;
177 }
178
179 // Unwraps the value and returns it. After this call the Result is invalid.
180 template <typename U = T>
181 typename std::enable_if<!std::is_void<U>::value, U>::type unwrap() {
182 CHECK(mValid) << "Result invalid";
183 mValid = false;
184 return std::move(*(mStorage.ok.ptr()));
185 }
186
187 // Unwraps the error and returns it. After this call the Result is invalid.
188 E unwrapErr() {
189 CHECK(mValid) << "Result invalid";
190 mValid = false;
191 return std::move(*(mStorage.err.ptr()));
192 }
193
194private:
195 detail::ResultStorage<T, E> mStorage;
196 bool mValid = true;
197};
198
199} // namespace base
200} // namespace android