blob: 64fa69f268c846589016cc585884d059255aee76 [file] [log] [blame]
Tom Cherry11a3aee2017-08-03 12:54:07 -07001/*
2 * Copyright (C) 2017 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// This file contains classes for returning a successful result along with an optional
18// arbitrarily typed return value or for returning a failure result along with an optional string
19// indicating why the function failed.
20
21// There are 3 classes that implement this functionality and one additional helper type.
22//
23// Result<T> either contains a member of type T that can be accessed using similar semantics as
24// std::optional<T> or it contains a std::string describing an error, which can be accessed via
25// Result<T>::error().
26//
27// Success is a typedef that aids in creating Result<T> that do not contain a return value.
28// Result<Success> is the correct return type for a function that either returns successfully or
29// returns an error value. Returning Success() from a function that returns Result<Success> is the
30// correct way to indicate that a function without a return type has completed successfully.
31//
32// A successful Result<T> is constructed implicitly from any type that can be implicitly converted
33// to T or from the constructor arguments for T. This allows you to return a type T directly from
34// a function that returns Result<T>.
35//
36// Error and ErrnoError are used to construct a Result<T> that has failed. Each of these classes
37// take an ostream as an input and are implicitly cast to a Result<T> containing that failure.
38// ErrnoError() additionally appends ": " + strerror(errno) to the end of the failure string to aid
39// in interacting with C APIs.
40
41// An example of how to use these is below:
42// Result<U> CalculateResult(const T& input) {
43// U output;
44// if (!SomeOtherCppFunction(input, &output)) {
45// return Error() << "SomeOtherCppFunction(" << input << ") failed";
46// }
47// if (!c_api_function(output)) {
48// return ErrnoError() << "c_api_function(" << output << ") failed";
49// }
50// return output;
51// }
52//
53// auto output = CalculateResult(input);
54// if (!output) return Error() << "CalculateResult failed: " << output.error();
55// UseOutput(*output);
56
57#ifndef _INIT_RESULT_H
58#define _INIT_RESULT_H
59
60#include <errno.h>
61
62#include <sstream>
63#include <string>
64#include <variant>
65
66namespace android {
67namespace init {
68
69class Error {
70 public:
71 Error() : append_errno_(0) {}
72
73 template <typename T>
74 Error&& operator<<(T&& t) {
75 ss_ << std::forward<T>(t);
76 return std::move(*this);
77 }
78
79 const std::string str() const {
80 if (append_errno_) {
81 return ss_.str() + ": " + strerror(append_errno_);
82 }
83 return ss_.str();
84 }
85
86 Error(const Error&) = delete;
87 Error(Error&&) = delete;
88 Error& operator=(const Error&) = delete;
89 Error& operator=(Error&&) = delete;
90
91 protected:
92 Error(int append_errno) : append_errno_(append_errno) {}
93
94 private:
95 std::stringstream ss_;
96 int append_errno_;
97};
98
99class ErrnoError : public Error {
100 public:
101 ErrnoError() : Error(errno) {}
102};
103
104template <typename T>
105class Result {
106 public:
107 template <typename... U>
108 Result(U&&... result) : contents_(std::in_place_index_t<0>(), std::forward<U>(result)...) {}
109
110 Result(Error&& fb) : contents_(std::in_place_index_t<1>(), fb.str()) {}
111
112 bool has_value() const { return contents_.index() == 0; }
113
114 T& value() & { return std::get<0>(contents_); }
115 const T& value() const & { return std::get<0>(contents_); }
116 T&& value() && { return std::get<0>(std::move(contents_)); }
117 const T&& value() const && { return std::get<0>(std::move(contents_)); }
118
119 const std::string& error() const & { return std::get<1>(contents_); }
120 std::string&& error() && { return std::get<1>(std::move(contents_)); }
121 const std::string&& error() const && { return std::get<1>(std::move(contents_)); }
122
123 explicit operator bool() const { return has_value(); }
124
125 T& operator*() & { return value(); }
126 const T& operator*() const & { return value(); }
127 T&& operator*() && { return std::move(value()); }
128 const T&& operator*() const && { return std::move(value()); }
129
130 T* operator->() { return &value(); }
131 const T* operator->() const { return &value(); }
132
133 private:
134 std::variant<T, std::string> contents_;
135};
136
137using Success = std::monostate;
138
139} // namespace init
140} // namespace android
141
142#endif