xref: /aosp_15_r20/external/federated-compute/fcp/base/result.h (revision 14675a029014e728ec732f129a32e299b2da0601)
1*14675a02SAndroid Build Coastguard Worker /*
2*14675a02SAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
3*14675a02SAndroid Build Coastguard Worker  *
4*14675a02SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*14675a02SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*14675a02SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*14675a02SAndroid Build Coastguard Worker  *
8*14675a02SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*14675a02SAndroid Build Coastguard Worker  *
10*14675a02SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*14675a02SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*14675a02SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*14675a02SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*14675a02SAndroid Build Coastguard Worker  * limitations under the License.
15*14675a02SAndroid Build Coastguard Worker  */
16*14675a02SAndroid Build Coastguard Worker 
17*14675a02SAndroid Build Coastguard Worker #ifndef FCP_BASE_RESULT_H_
18*14675a02SAndroid Build Coastguard Worker #define FCP_BASE_RESULT_H_
19*14675a02SAndroid Build Coastguard Worker 
20*14675a02SAndroid Build Coastguard Worker #include <optional>
21*14675a02SAndroid Build Coastguard Worker #include <type_traits>
22*14675a02SAndroid Build Coastguard Worker #include <variant>
23*14675a02SAndroid Build Coastguard Worker 
24*14675a02SAndroid Build Coastguard Worker #include "fcp/base/error.h"
25*14675a02SAndroid Build Coastguard Worker #include "fcp/base/meta.h"
26*14675a02SAndroid Build Coastguard Worker #include "fcp/base/source_location.h"
27*14675a02SAndroid Build Coastguard Worker 
28*14675a02SAndroid Build Coastguard Worker namespace fcp {
29*14675a02SAndroid Build Coastguard Worker namespace result_internal {
30*14675a02SAndroid Build Coastguard Worker 
31*14675a02SAndroid Build Coastguard Worker template <typename R>
32*14675a02SAndroid Build Coastguard Worker struct ResultTraits;
33*14675a02SAndroid Build Coastguard Worker 
34*14675a02SAndroid Build Coastguard Worker }  // namespace result_internal
35*14675a02SAndroid Build Coastguard Worker 
36*14675a02SAndroid Build Coastguard Worker // A Result is either a value (T) or an opaque Error. There are two main ways to
37*14675a02SAndroid Build Coastguard Worker // use one.
38*14675a02SAndroid Build Coastguard Worker //
39*14675a02SAndroid Build Coastguard Worker // Transform: Given a Result<T> r, and a callable f from T to Result<U>,
40*14675a02SAndroid Build Coastguard Worker // r.Then(f) returns Result<U>. Note that errors are passed through (without
41*14675a02SAndroid Build Coastguard Worker // calling f).
42*14675a02SAndroid Build Coastguard Worker //
43*14675a02SAndroid Build Coastguard Worker // Similarly, given a Result<T> r, and a callable f from T to U, r.Map(f)
44*14675a02SAndroid Build Coastguard Worker // returns Result<U>. The difference is that Then can introduce new errors (it
45*14675a02SAndroid Build Coastguard Worker // returns Result<U>) whereas Map only transforms values to other values.
46*14675a02SAndroid Build Coastguard Worker //
47*14675a02SAndroid Build Coastguard Worker //  Result<int> some_int = ...
48*14675a02SAndroid Build Coastguard Worker //  Result<bool> b = some_int.Then([](int i) -> Result<int> {
49*14675a02SAndroid Build Coastguard Worker //    if (i < 0) {
50*14675a02SAndroid Build Coastguard Worker //      return TraceError<...>(...);
51*14675a02SAndroid Build Coastguard Worker //    } else {
52*14675a02SAndroid Build Coastguard Worker //      return i;
53*14675a02SAndroid Build Coastguard Worker //    }
54*14675a02SAndroid Build Coastguard Worker //  }).Map([](int i) -> bool) {
55*14675a02SAndroid Build Coastguard Worker //    return i % 2 == 0;
56*14675a02SAndroid Build Coastguard Worker //  });
57*14675a02SAndroid Build Coastguard Worker //
58*14675a02SAndroid Build Coastguard Worker // Propagate: The FCP_TRY macro unwraps results to their values. If a result
59*14675a02SAndroid Build Coastguard Worker // contains an error, it is returned (from the function where FCP_TRY appears).
60*14675a02SAndroid Build Coastguard Worker //
61*14675a02SAndroid Build Coastguard Worker //   Result<int> GetInt();
62*14675a02SAndroid Build Coastguard Worker //
63*14675a02SAndroid Build Coastguard Worker //   Result<bool> F() {
64*14675a02SAndroid Build Coastguard Worker //     int i = FCP_TRY(GetInt());
65*14675a02SAndroid Build Coastguard Worker //     if (i < 0) {
66*14675a02SAndroid Build Coastguard Worker //     }
67*14675a02SAndroid Build Coastguard Worker //
68*14675a02SAndroid Build Coastguard Worker //     return i % 2 == 0;
69*14675a02SAndroid Build Coastguard Worker //   }
70*14675a02SAndroid Build Coastguard Worker //
71*14675a02SAndroid Build Coastguard Worker // Result<T> provides implicit conversions from T and Error. As above, in
72*14675a02SAndroid Build Coastguard Worker // functions returning Result<T>, it is useful and encourage to return a T or
73*14675a02SAndroid Build Coastguard Worker // Error directly.
74*14675a02SAndroid Build Coastguard Worker template <typename T>
75*14675a02SAndroid Build Coastguard Worker class ABSL_MUST_USE_RESULT Result {
76*14675a02SAndroid Build Coastguard Worker  public:
77*14675a02SAndroid Build Coastguard Worker   using ValueType = T;
78*14675a02SAndroid Build Coastguard Worker 
79*14675a02SAndroid Build Coastguard Worker   // These make Result<> usable as an argument to Match() (see match.h).
80*14675a02SAndroid Build Coastguard Worker   using VariantType = std::variant<Error, T>;
variant()81*14675a02SAndroid Build Coastguard Worker   constexpr VariantType& variant() & { return val_; }
variant()82*14675a02SAndroid Build Coastguard Worker   constexpr VariantType const& variant() const& { return val_; }
variant()83*14675a02SAndroid Build Coastguard Worker   constexpr VariantType&& variant() && { return std::move(val_); }
84*14675a02SAndroid Build Coastguard Worker 
85*14675a02SAndroid Build Coastguard Worker   // Implicit conversion from T
Result(T t)86*14675a02SAndroid Build Coastguard Worker   constexpr Result(T t) : val_(std::move(t)) {}  // NOLINT
87*14675a02SAndroid Build Coastguard Worker 
88*14675a02SAndroid Build Coastguard Worker   // Implicit conversion from Error
Result(Error e)89*14675a02SAndroid Build Coastguard Worker   Result(Error e) : val_(e) {}  // NOLINT
90*14675a02SAndroid Build Coastguard Worker 
is_error()91*14675a02SAndroid Build Coastguard Worker   constexpr bool is_error() const {
92*14675a02SAndroid Build Coastguard Worker     return std::holds_alternative<Error>(val_);
93*14675a02SAndroid Build Coastguard Worker   }
94*14675a02SAndroid Build Coastguard Worker 
95*14675a02SAndroid Build Coastguard Worker   // Returns a *reference* to the contained value.
96*14675a02SAndroid Build Coastguard Worker   // Requires (CHECK): !is_error()
GetValueOrDie()97*14675a02SAndroid Build Coastguard Worker   constexpr T const& GetValueOrDie() const& {
98*14675a02SAndroid Build Coastguard Worker     FCP_CHECK(std::holds_alternative<T>(val_));
99*14675a02SAndroid Build Coastguard Worker     return absl::get<T>(val_);
100*14675a02SAndroid Build Coastguard Worker   }
101*14675a02SAndroid Build Coastguard Worker 
102*14675a02SAndroid Build Coastguard Worker   // Returns the contained value (by move).
103*14675a02SAndroid Build Coastguard Worker   // This applies for results which are rvalues.
104*14675a02SAndroid Build Coastguard Worker   //
105*14675a02SAndroid Build Coastguard Worker   // Example:
106*14675a02SAndroid Build Coastguard Worker   //   Result<X> r = f();
107*14675a02SAndroid Build Coastguard Worker   //   X v = std::move(r).GetValueOrDie();
108*14675a02SAndroid Build Coastguard Worker   //
109*14675a02SAndroid Build Coastguard Worker   // Example:
110*14675a02SAndroid Build Coastguard Worker   //   X v = f().GetValueOrDie();
111*14675a02SAndroid Build Coastguard Worker   //
112*14675a02SAndroid Build Coastguard Worker   // Requires (CHECK): !is_error()
GetValueOrDie()113*14675a02SAndroid Build Coastguard Worker   constexpr T GetValueOrDie() && {
114*14675a02SAndroid Build Coastguard Worker     FCP_CHECK(std::holds_alternative<T>(val_));
115*14675a02SAndroid Build Coastguard Worker     return absl::get<T>(std::move(val_));
116*14675a02SAndroid Build Coastguard Worker   }
117*14675a02SAndroid Build Coastguard Worker 
118*14675a02SAndroid Build Coastguard Worker   // Returns the contained error.
119*14675a02SAndroid Build Coastguard Worker   // Requires (CHECK): is_error()
GetErrorOrDie()120*14675a02SAndroid Build Coastguard Worker   Error GetErrorOrDie() const {
121*14675a02SAndroid Build Coastguard Worker     FCP_CHECK(std::holds_alternative<Error>(val_));
122*14675a02SAndroid Build Coastguard Worker     return absl::get<Error>(val_);
123*14675a02SAndroid Build Coastguard Worker   }
124*14675a02SAndroid Build Coastguard Worker 
125*14675a02SAndroid Build Coastguard Worker   // Transforms this Result into another (with value type U).
126*14675a02SAndroid Build Coastguard Worker   //
127*14675a02SAndroid Build Coastguard Worker   // If this Result holds an Error, it is passed through.
128*14675a02SAndroid Build Coastguard Worker   // If this Result holds a value, then the callable 'fn' is applied to it.
129*14675a02SAndroid Build Coastguard Worker   // The callable 'fn' is expected to return Result<U>.
130*14675a02SAndroid Build Coastguard Worker   //
131*14675a02SAndroid Build Coastguard Worker   // Example:
132*14675a02SAndroid Build Coastguard Worker   //
133*14675a02SAndroid Build Coastguard Worker   //  Result<int> some_int = ...
134*14675a02SAndroid Build Coastguard Worker   //  Result<bool> b = some_int.Then([](int i) -> Result<bool> {
135*14675a02SAndroid Build Coastguard Worker   //    if (i < 0) {
136*14675a02SAndroid Build Coastguard Worker   //      return TraceError<...>(...);
137*14675a02SAndroid Build Coastguard Worker   //    } else {
138*14675a02SAndroid Build Coastguard Worker   //      return i % 2 == 0;
139*14675a02SAndroid Build Coastguard Worker   //    }
140*14675a02SAndroid Build Coastguard Worker   //  });
141*14675a02SAndroid Build Coastguard Worker   template <typename Fn>
Then(Fn fn)142*14675a02SAndroid Build Coastguard Worker   constexpr auto Then(Fn fn) const& {
143*14675a02SAndroid Build Coastguard Worker     return ThenInternal<false>(*this, std::move(fn));
144*14675a02SAndroid Build Coastguard Worker   }
145*14675a02SAndroid Build Coastguard Worker 
146*14675a02SAndroid Build Coastguard Worker   template <typename Fn>
Then(Fn fn)147*14675a02SAndroid Build Coastguard Worker   constexpr auto Then(Fn fn) && {
148*14675a02SAndroid Build Coastguard Worker     return ThenInternal<true>(std::move(*this), std::move(fn));
149*14675a02SAndroid Build Coastguard Worker   }
150*14675a02SAndroid Build Coastguard Worker 
151*14675a02SAndroid Build Coastguard Worker   // Maps values of type T to a values of type U.
152*14675a02SAndroid Build Coastguard Worker   //
153*14675a02SAndroid Build Coastguard Worker   // If this Result holds an Error, it is passed through.
154*14675a02SAndroid Build Coastguard Worker   // If this Result holds a value, then the callable 'fn' is applied to it.
155*14675a02SAndroid Build Coastguard Worker   //
156*14675a02SAndroid Build Coastguard Worker   // Example:
157*14675a02SAndroid Build Coastguard Worker   //
158*14675a02SAndroid Build Coastguard Worker   //  Result<int> some_int = ...
159*14675a02SAndroid Build Coastguard Worker   //  Result<bool> b = some_int.Map([](int i) {
160*14675a02SAndroid Build Coastguard Worker   //    return i % 2 == 0;
161*14675a02SAndroid Build Coastguard Worker   //  });
162*14675a02SAndroid Build Coastguard Worker   template <typename Fn>
Map(Fn fn)163*14675a02SAndroid Build Coastguard Worker   constexpr auto Map(Fn fn) const& {
164*14675a02SAndroid Build Coastguard Worker     using U = std::invoke_result_t<Fn, T const&>;
165*14675a02SAndroid Build Coastguard Worker     return ThenInternal<false>(
166*14675a02SAndroid Build Coastguard Worker         *this, [fn = std::move(fn)](T const& t) { return Result<U>(fn(t)); });
167*14675a02SAndroid Build Coastguard Worker   }
168*14675a02SAndroid Build Coastguard Worker 
169*14675a02SAndroid Build Coastguard Worker   template <typename Fn>
Map(Fn fn)170*14675a02SAndroid Build Coastguard Worker   constexpr auto Map(Fn fn) && {
171*14675a02SAndroid Build Coastguard Worker     using U = std::invoke_result_t<Fn, T&&>;
172*14675a02SAndroid Build Coastguard Worker     return ThenInternal<true>(std::move(*this), [fn = std::move(fn)](T&& t) {
173*14675a02SAndroid Build Coastguard Worker       return Result<U>(fn(std::move(t)));
174*14675a02SAndroid Build Coastguard Worker     });
175*14675a02SAndroid Build Coastguard Worker   }
176*14675a02SAndroid Build Coastguard Worker 
177*14675a02SAndroid Build Coastguard Worker  private:
178*14675a02SAndroid Build Coastguard Worker   template <bool Move, typename Fn>
ThenInternal(std::conditional_t<Move,Result<T> &&,Result<T> const &> r,Fn fn)179*14675a02SAndroid Build Coastguard Worker   static constexpr auto ThenInternal(
180*14675a02SAndroid Build Coastguard Worker       std::conditional_t<Move, Result<T>&&, Result<T> const&> r, Fn fn) {
181*14675a02SAndroid Build Coastguard Worker     using RefType = std::conditional_t<Move, T&&, T const&>;
182*14675a02SAndroid Build Coastguard Worker     using RetType = std::invoke_result_t<Fn, RefType>;
183*14675a02SAndroid Build Coastguard Worker     static_assert(
184*14675a02SAndroid Build Coastguard Worker         result_internal::ResultTraits<RetType>::is_result(),
185*14675a02SAndroid Build Coastguard Worker         "The callable provided to 'Then' must return Result<U> for "
186*14675a02SAndroid Build Coastguard Worker         "some type U. When always returning a value, use Map instead.");
187*14675a02SAndroid Build Coastguard Worker 
188*14675a02SAndroid Build Coastguard Worker     if (r.is_error()) {
189*14675a02SAndroid Build Coastguard Worker       return RetType(r.GetErrorOrDie());
190*14675a02SAndroid Build Coastguard Worker     } else {
191*14675a02SAndroid Build Coastguard Worker       return fn(absl::get<T>(std::move(r).variant()));
192*14675a02SAndroid Build Coastguard Worker     }
193*14675a02SAndroid Build Coastguard Worker   }
194*14675a02SAndroid Build Coastguard Worker 
195*14675a02SAndroid Build Coastguard Worker   std::variant<Error, T> val_;
196*14675a02SAndroid Build Coastguard Worker };
197*14675a02SAndroid Build Coastguard Worker 
198*14675a02SAndroid Build Coastguard Worker // This is a deduction guide so that one can write Result(t) for a value t,
199*14675a02SAndroid Build Coastguard Worker // without explicitly specifying the value type. This one is implicitly
200*14675a02SAndroid Build Coastguard Worker // declared anyway; we make it explicit to suppress -Wctad-maybe-unsupported.
201*14675a02SAndroid Build Coastguard Worker template <typename T>
202*14675a02SAndroid Build Coastguard Worker Result(T) -> Result<T>;
203*14675a02SAndroid Build Coastguard Worker 
204*14675a02SAndroid Build Coastguard Worker // ResultFrom<T> -> Result<T>
205*14675a02SAndroid Build Coastguard Worker // ResultFrom<Result<T>> -> Result<T>
206*14675a02SAndroid Build Coastguard Worker //
207*14675a02SAndroid Build Coastguard Worker // Note that ResultFrom<Error> is ill-formed (like Result<Error>).
208*14675a02SAndroid Build Coastguard Worker template <typename T>
209*14675a02SAndroid Build Coastguard Worker using ResultFrom = decltype(Result(std::declval<T>()));
210*14675a02SAndroid Build Coastguard Worker 
211*14675a02SAndroid Build Coastguard Worker // ResultOf applied to the result of calling Fn with Args...
212*14675a02SAndroid Build Coastguard Worker template <typename Fn, typename... Args>
213*14675a02SAndroid Build Coastguard Worker using ResultOf = ResultFrom<std::invoke_result_t<Fn, Args...>>;
214*14675a02SAndroid Build Coastguard Worker 
215*14675a02SAndroid Build Coastguard Worker namespace result_internal {
216*14675a02SAndroid Build Coastguard Worker 
217*14675a02SAndroid Build Coastguard Worker template <typename R>
218*14675a02SAndroid Build Coastguard Worker struct ResultTraits {
219*14675a02SAndroid Build Coastguard Worker   using ValueType = void;
220*14675a02SAndroid Build Coastguard Worker };
221*14675a02SAndroid Build Coastguard Worker 
222*14675a02SAndroid Build Coastguard Worker template <typename T>
223*14675a02SAndroid Build Coastguard Worker struct ResultTraits<Result<T>> {
224*14675a02SAndroid Build Coastguard Worker   static constexpr bool is_result() { return true; }
225*14675a02SAndroid Build Coastguard Worker   using ValueType = T;
226*14675a02SAndroid Build Coastguard Worker };
227*14675a02SAndroid Build Coastguard Worker 
228*14675a02SAndroid Build Coastguard Worker // This is used in FCP_TRY, to require that the parameter to FCP_TRY has type
229*14675a02SAndroid Build Coastguard Worker // Result<T> for some T.
230*14675a02SAndroid Build Coastguard Worker template <typename T>
231*14675a02SAndroid Build Coastguard Worker constexpr bool ResultIsError(Result<T> const& r) {
232*14675a02SAndroid Build Coastguard Worker   return r.is_error();
233*14675a02SAndroid Build Coastguard Worker }
234*14675a02SAndroid Build Coastguard Worker 
235*14675a02SAndroid Build Coastguard Worker }  // namespace result_internal
236*14675a02SAndroid Build Coastguard Worker 
237*14675a02SAndroid Build Coastguard Worker class ExpectBase {
238*14675a02SAndroid Build Coastguard Worker  public:
239*14675a02SAndroid Build Coastguard Worker   constexpr explicit ExpectBase(SourceLocation loc) : loc_(loc) {}
240*14675a02SAndroid Build Coastguard Worker 
241*14675a02SAndroid Build Coastguard Worker  protected:
242*14675a02SAndroid Build Coastguard Worker   Error TraceExpectError(const char* expectation) const;
243*14675a02SAndroid Build Coastguard Worker   Error TraceUnexpectedStatus(fcp::StatusCode expected_code,
244*14675a02SAndroid Build Coastguard Worker                               const fcp::Status& actual) const;
245*14675a02SAndroid Build Coastguard Worker 
246*14675a02SAndroid Build Coastguard Worker  private:
247*14675a02SAndroid Build Coastguard Worker   SourceLocation loc_;
248*14675a02SAndroid Build Coastguard Worker };
249*14675a02SAndroid Build Coastguard Worker 
250*14675a02SAndroid Build Coastguard Worker // Returns Result<T> if the current result has std::variant that holds a
251*14675a02SAndroid Build Coastguard Worker // value of type T; otherwise returns an error Result.
252*14675a02SAndroid Build Coastguard Worker template <typename T>
253*14675a02SAndroid Build Coastguard Worker struct ExpectIs : public ExpectBase {
254*14675a02SAndroid Build Coastguard Worker   using ExpectBase::ExpectBase;
255*14675a02SAndroid Build Coastguard Worker   constexpr explicit ExpectIs(SourceLocation loc = SourceLocation::current())
256*14675a02SAndroid Build Coastguard Worker       : ExpectBase(loc) {}
257*14675a02SAndroid Build Coastguard Worker 
258*14675a02SAndroid Build Coastguard Worker   template <typename... Us>
259*14675a02SAndroid Build Coastguard Worker   constexpr Result<T> operator()(std::variant<Us...> v) const {
260*14675a02SAndroid Build Coastguard Worker     if (std::holds_alternative<T>(v)) {
261*14675a02SAndroid Build Coastguard Worker       return absl::get<T>(std::move(v));
262*14675a02SAndroid Build Coastguard Worker     } else {
263*14675a02SAndroid Build Coastguard Worker       return TraceExpectError("ExpectIs");
264*14675a02SAndroid Build Coastguard Worker     }
265*14675a02SAndroid Build Coastguard Worker   }
266*14675a02SAndroid Build Coastguard Worker };
267*14675a02SAndroid Build Coastguard Worker 
268*14675a02SAndroid Build Coastguard Worker // Returns Result<std::variant<Us...>> if the current result has
269*14675a02SAndroid Build Coastguard Worker // std::variant that holds a value of one of the types from Us... typelist;
270*14675a02SAndroid Build Coastguard Worker // otherwise returns an error Result. This operation is valid only when the
271*14675a02SAndroid Build Coastguard Worker // set of expected types Us... is a subset of the set of types Ts... in the
272*14675a02SAndroid Build Coastguard Worker // current result.
273*14675a02SAndroid Build Coastguard Worker template <typename... Ts>
274*14675a02SAndroid Build Coastguard Worker struct ExpectOneOf : public ExpectBase {
275*14675a02SAndroid Build Coastguard Worker   using ExpectBase::ExpectBase;
276*14675a02SAndroid Build Coastguard Worker   constexpr explicit ExpectOneOf(SourceLocation loc = SourceLocation::current())
277*14675a02SAndroid Build Coastguard Worker       : ExpectBase(loc) {}
278*14675a02SAndroid Build Coastguard Worker 
279*14675a02SAndroid Build Coastguard Worker   template <typename... Us>
280*14675a02SAndroid Build Coastguard Worker   constexpr Result<std::variant<Ts...>> operator()(
281*14675a02SAndroid Build Coastguard Worker       std::variant<Us...> v) const {
282*14675a02SAndroid Build Coastguard Worker     static_assert(IsSubsetOf<Pack<Ts...>, Pack<Us...>>::value);
283*14675a02SAndroid Build Coastguard Worker 
284*14675a02SAndroid Build Coastguard Worker     // TODO(team): This should be expressible with Match
285*14675a02SAndroid Build Coastguard Worker     return absl::visit(
286*14675a02SAndroid Build Coastguard Worker         [this](auto arg) -> Result<std::variant<Ts...>> {
287*14675a02SAndroid Build Coastguard Worker           if constexpr (IsTypeOneOf<std::decay_t<decltype(arg)>, Ts...>()) {
288*14675a02SAndroid Build Coastguard Worker             return std::variant<Ts...>(std::move(arg));
289*14675a02SAndroid Build Coastguard Worker           } else {
290*14675a02SAndroid Build Coastguard Worker             return TraceExpectError("ExpectOneOf<>");
291*14675a02SAndroid Build Coastguard Worker           }
292*14675a02SAndroid Build Coastguard Worker         },
293*14675a02SAndroid Build Coastguard Worker         std::move(v));
294*14675a02SAndroid Build Coastguard Worker   }
295*14675a02SAndroid Build Coastguard Worker };
296*14675a02SAndroid Build Coastguard Worker 
297*14675a02SAndroid Build Coastguard Worker // Returns Result<Unit> if the current result has boolean 'true' value;
298*14675a02SAndroid Build Coastguard Worker // otherwise returns an error Result.
299*14675a02SAndroid Build Coastguard Worker struct ExpectTrue : public ExpectBase {
300*14675a02SAndroid Build Coastguard Worker   using ExpectBase::ExpectBase;
301*14675a02SAndroid Build Coastguard Worker   constexpr explicit ExpectTrue(SourceLocation loc = SourceLocation::current())
302*14675a02SAndroid Build Coastguard Worker       : ExpectBase(loc) {}
303*14675a02SAndroid Build Coastguard Worker 
304*14675a02SAndroid Build Coastguard Worker   template <typename... Us>
305*14675a02SAndroid Build Coastguard Worker   constexpr Result<Unit> operator()(bool b) const {
306*14675a02SAndroid Build Coastguard Worker     if (b) {
307*14675a02SAndroid Build Coastguard Worker       return Unit{};
308*14675a02SAndroid Build Coastguard Worker     } else {
309*14675a02SAndroid Build Coastguard Worker       return TraceExpectError("ExpectTrue");
310*14675a02SAndroid Build Coastguard Worker     }
311*14675a02SAndroid Build Coastguard Worker   }
312*14675a02SAndroid Build Coastguard Worker };
313*14675a02SAndroid Build Coastguard Worker 
314*14675a02SAndroid Build Coastguard Worker // Returns Result<Unit> if the current result has boolean 'false' value;
315*14675a02SAndroid Build Coastguard Worker // otherwise returns an error Result.
316*14675a02SAndroid Build Coastguard Worker struct ExpectFalse : public ExpectBase {
317*14675a02SAndroid Build Coastguard Worker   using ExpectBase::ExpectBase;
318*14675a02SAndroid Build Coastguard Worker   constexpr explicit ExpectFalse(SourceLocation loc = SourceLocation::current())
319*14675a02SAndroid Build Coastguard Worker       : ExpectBase(loc) {}
320*14675a02SAndroid Build Coastguard Worker 
321*14675a02SAndroid Build Coastguard Worker   template <typename... Us>
322*14675a02SAndroid Build Coastguard Worker   constexpr Result<Unit> operator()(bool b) const {
323*14675a02SAndroid Build Coastguard Worker     if (!b) {
324*14675a02SAndroid Build Coastguard Worker       return Unit{};
325*14675a02SAndroid Build Coastguard Worker     } else {
326*14675a02SAndroid Build Coastguard Worker       return TraceExpectError("ExpectTrue");
327*14675a02SAndroid Build Coastguard Worker     }
328*14675a02SAndroid Build Coastguard Worker   }
329*14675a02SAndroid Build Coastguard Worker };
330*14675a02SAndroid Build Coastguard Worker 
331*14675a02SAndroid Build Coastguard Worker // Returns Result<T> if the current result has std::optional<T> has a value;
332*14675a02SAndroid Build Coastguard Worker // otherwise returns an error Result.
333*14675a02SAndroid Build Coastguard Worker struct ExpectHasValue : public ExpectBase {
334*14675a02SAndroid Build Coastguard Worker   using ExpectBase::ExpectBase;
335*14675a02SAndroid Build Coastguard Worker   constexpr explicit ExpectHasValue(
336*14675a02SAndroid Build Coastguard Worker       SourceLocation loc = SourceLocation::current())
337*14675a02SAndroid Build Coastguard Worker       : ExpectBase(loc) {}
338*14675a02SAndroid Build Coastguard Worker 
339*14675a02SAndroid Build Coastguard Worker   template <typename T>
340*14675a02SAndroid Build Coastguard Worker   constexpr Result<T> operator()(std::optional<T> v) const {
341*14675a02SAndroid Build Coastguard Worker     if (v.has_value()) {
342*14675a02SAndroid Build Coastguard Worker       return *std::move(v);
343*14675a02SAndroid Build Coastguard Worker     } else {
344*14675a02SAndroid Build Coastguard Worker       return TraceExpectError("ExpectHasValue");
345*14675a02SAndroid Build Coastguard Worker     }
346*14675a02SAndroid Build Coastguard Worker   }
347*14675a02SAndroid Build Coastguard Worker };
348*14675a02SAndroid Build Coastguard Worker 
349*14675a02SAndroid Build Coastguard Worker // Returns Result<Unit> if the current result has an empty std::optional;
350*14675a02SAndroid Build Coastguard Worker // otherwise returns an error Result.
351*14675a02SAndroid Build Coastguard Worker struct ExpectIsEmpty : public ExpectBase {
352*14675a02SAndroid Build Coastguard Worker   using ExpectBase::ExpectBase;
353*14675a02SAndroid Build Coastguard Worker   constexpr explicit ExpectIsEmpty(
354*14675a02SAndroid Build Coastguard Worker       SourceLocation loc = SourceLocation::current())
355*14675a02SAndroid Build Coastguard Worker       : ExpectBase(loc) {}
356*14675a02SAndroid Build Coastguard Worker 
357*14675a02SAndroid Build Coastguard Worker   template <typename T>
358*14675a02SAndroid Build Coastguard Worker   constexpr Result<Unit> operator()(std::optional<T> v) const {
359*14675a02SAndroid Build Coastguard Worker     if (!v.has_value()) {
360*14675a02SAndroid Build Coastguard Worker       return Unit{};
361*14675a02SAndroid Build Coastguard Worker     } else {
362*14675a02SAndroid Build Coastguard Worker       return TraceExpectError("ExpectIsEmpty");
363*14675a02SAndroid Build Coastguard Worker     }
364*14675a02SAndroid Build Coastguard Worker   }
365*14675a02SAndroid Build Coastguard Worker };
366*14675a02SAndroid Build Coastguard Worker 
367*14675a02SAndroid Build Coastguard Worker struct ExpectOk : public ExpectBase {
368*14675a02SAndroid Build Coastguard Worker   using ExpectBase::ExpectBase;
369*14675a02SAndroid Build Coastguard Worker   constexpr explicit ExpectOk(SourceLocation loc = SourceLocation::current())
370*14675a02SAndroid Build Coastguard Worker       : ExpectBase(loc) {}
371*14675a02SAndroid Build Coastguard Worker 
372*14675a02SAndroid Build Coastguard Worker   template <typename T>
373*14675a02SAndroid Build Coastguard Worker   constexpr Result<T> operator()(StatusOr<T> s) const {
374*14675a02SAndroid Build Coastguard Worker     if (s.ok()) {
375*14675a02SAndroid Build Coastguard Worker       return std::move(s).value();
376*14675a02SAndroid Build Coastguard Worker     } else {
377*14675a02SAndroid Build Coastguard Worker       return TraceUnexpectedStatus(fcp::OK, s.status());
378*14675a02SAndroid Build Coastguard Worker     }
379*14675a02SAndroid Build Coastguard Worker   }
380*14675a02SAndroid Build Coastguard Worker 
381*14675a02SAndroid Build Coastguard Worker   Result<Unit> operator()(const Status& s) const {
382*14675a02SAndroid Build Coastguard Worker     if (s.code() == fcp::OK) {
383*14675a02SAndroid Build Coastguard Worker       return Unit{};
384*14675a02SAndroid Build Coastguard Worker     } else {
385*14675a02SAndroid Build Coastguard Worker       return TraceUnexpectedStatus(fcp::OK, s);
386*14675a02SAndroid Build Coastguard Worker     }
387*14675a02SAndroid Build Coastguard Worker   }
388*14675a02SAndroid Build Coastguard Worker };
389*14675a02SAndroid Build Coastguard Worker 
390*14675a02SAndroid Build Coastguard Worker }  // namespace fcp
391*14675a02SAndroid Build Coastguard Worker 
392*14675a02SAndroid Build Coastguard Worker #define FCP_TRY(...)                                             \
393*14675a02SAndroid Build Coastguard Worker   ({                                                             \
394*14675a02SAndroid Build Coastguard Worker     auto try_tmp_value_ = (__VA_ARGS__);                         \
395*14675a02SAndroid Build Coastguard Worker     if (::fcp::result_internal::ResultIsError(try_tmp_value_)) { \
396*14675a02SAndroid Build Coastguard Worker       return try_tmp_value_.GetErrorOrDie();                     \
397*14675a02SAndroid Build Coastguard Worker     }                                                            \
398*14675a02SAndroid Build Coastguard Worker     std::move(try_tmp_value_).GetValueOrDie();                   \
399*14675a02SAndroid Build Coastguard Worker   })
400*14675a02SAndroid Build Coastguard Worker 
401*14675a02SAndroid Build Coastguard Worker #endif  // FCP_BASE_RESULT_H_
402