• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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