• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
57 namespace android {
58 namespace base {
59 
60 namespace detail {
61 
62 template <typename T>
63 struct Ok {
OkOk64     Ok(const T& value) : value(value) {}
OkOk65     Ok(T&& value) : value(std::move(value)) {}
66 
OkOk67     Ok(Ok&& other) : value(std::move(other.value)) {}
68 
69     T value;
70 };
71 
72 template <>
73 struct Ok<void> {
74     Ok() = default;
75 };
76 
77 template <typename E>
78 struct Err {
79 public:
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 
88 template <typename T, typename E>
89 struct 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 
103 template <typename E>
104 struct 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 
115 template <typename T, typename Value = typename std::decay<T>::type>
116 detail::Ok<Value> Ok(T&& value) {
117     return detail::Ok<Value>(std::forward<T>(value));
118 }
119 
120 static inline detail::Ok<void> Ok() {
121     return detail::Ok<void>();
122 }
123 
124 template <typename E, typename Value = typename std::decay<E>::type>
125 detail::Err<Value> Err(E&& value) {
126     return detail::Err<Value>(std::forward<E>(value));
127 }
128 
129 template <typename T, typename E>
130 class Result {
131 public:
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 
194 private:
195     detail::ResultStorage<T, E> mStorage;
196     bool mValid = true;
197 };
198 
199 }  // namespace base
200 }  // namespace android
201