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