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