1 /* 2 * Copyright 2021 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 17 #pragma once 18 19 #include <optional> 20 21 #include <keymaster/logger.h> 22 23 namespace keymaster { 24 25 /** 26 * KmErrorOr contains either a keymaster_error_t or a value of type `T`. 27 * 28 * KmErrorOr values must be checked, or the destructor will log a messange and abort. They may be 29 * checked by calling `isOk()`, which returns true iff the object contains a value rather than 30 * an error, or by using the conversion to bool operator. 31 * 32 * After checking, the value may be retrieved using the value() methods or the operator-> or 33 * operator* methods, as users of std::optional, etc., would expect. 34 */ 35 template <typename T> class KmErrorOr { 36 public: 37 // Construct empty, typically to move another error into later. Default-constructed KmErrorOr's 38 // don't need to be checked. You can't get a value from them, though; that will crash. KmErrorOr()39 KmErrorOr() : error_(KM_ERROR_UNKNOWN_ERROR), value_checked_(true) {} 40 41 // Construct from error. KmErrorOr(keymaster_error_t error)42 KmErrorOr(keymaster_error_t error) : error_(error) {} // NOLINT(google-explicit-constructor) 43 44 // Construct from value. KmErrorOr(const T & value)45 KmErrorOr(const T& value) : value_(value) {} // NOLINT(google-explicit-constructor) KmErrorOr(T && value)46 KmErrorOr(T&& value) : value_(std::move(value)) {} // NOLINT(google-explicit-constructor) 47 48 // Move-construct or move-assign KmErrorOr(KmErrorOr && other)49 KmErrorOr(KmErrorOr&& other) { // NOLINT(google-explicit-constructor) 50 error_ = KM_ERROR_UNKNOWN_ERROR; 51 value_checked_ = true; 52 operator=(std::move(other)); 53 } 54 KmErrorOr& operator=(KmErrorOr&& other) { 55 if (&other == this) return *this; 56 57 std::swap(error_, other.error_); 58 std::swap(value_, other.value_); 59 std::swap(value_checked_, other.value_checked_); 60 61 return *this; 62 } 63 64 // Don't copy. 65 KmErrorOr(const KmErrorOr&) = delete; 66 void operator=(const KmErrorOr&) = delete; 67 ~KmErrorOr()68 ~KmErrorOr() { 69 if (!value_checked_) { 70 LOG_S("KmErrorOr not checked", 0); 71 abort(); 72 } 73 } 74 isOk()75 bool isOk() const { 76 value_checked_ = true; 77 return value_.has_value(); 78 } 79 operator bool() const { return isOk(); } // NOLINT(google-explicit-constructor) 80 error()81 keymaster_error_t error() { return value_checked_ ? error_ : KM_ERROR_UNKNOWN_ERROR; }; 82 value()83 T& value() & { return value_.value(); } value()84 const T& value() const& { return value_.value(); } value()85 T&& value() && { return value_.value(); } value()86 const T&& value() const&& { return value_.value(); } 87 88 T* operator->() { return &value_.value(); } 89 const T* operator->() const { return &value_.value(); } 90 91 T& operator*() & { return value_.value(); } 92 const T& operator*() const& { return value_.value(); } 93 T&& operator*() && { return std::move(value_).value(); } 94 95 private: 96 keymaster_error_t error_ = KM_ERROR_OK; 97 std::optional<T> value_; 98 mutable bool value_checked_ = false; 99 }; 100 101 } // namespace keymaster 102