/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Like folly::Optional, but can store a value *or* an error. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FOLLY_EXPECTED_ID(X) FB_CONCATENATE(FB_CONCATENATE(Folly, X), __LINE__) #define FOLLY_REQUIRES_IMPL(...) \ bool FOLLY_EXPECTED_ID(Requires) = false, \ typename std::enable_if< \ (FOLLY_EXPECTED_ID(Requires) || static_cast(__VA_ARGS__)), \ int>::type = 0 #define FOLLY_REQUIRES_TRAILING(...) , FOLLY_REQUIRES_IMPL(__VA_ARGS__) #define FOLLY_REQUIRES(...) template namespace folly { namespace expected_detail { namespace expected_detail_ExpectedHelper { struct ExpectedHelper; } /* using override */ using expected_detail_ExpectedHelper::ExpectedHelper; } // namespace expected_detail /** * Unexpected - a helper type used to disambiguate the construction of * Expected objects in the error state. */ template class Unexpected final { template friend class Unexpected; template friend class Expected; friend struct expected_detail::ExpectedHelper; public: /** * Constructors */ Unexpected() = default; Unexpected(const Unexpected&) = default; Unexpected(Unexpected&&) = default; Unexpected& operator=(const Unexpected&) = default; Unexpected& operator=(Unexpected&&) = default; FOLLY_COLD constexpr /* implicit */ Unexpected(const Error& err) : error_(err) {} FOLLY_COLD constexpr /* implicit */ Unexpected(Error&& err) : error_(std::move(err)) {} template ::value)> constexpr /* implicit */ Unexpected(Unexpected that) : error_(std::move(that.error())) {} /** * Assignment */ template ::value)> Unexpected& operator=(Unexpected that) { error_ = std::move(that.error()); } /** * Observers */ Error& error() & { return error_; } const Error& error() const& { return error_; } Error&& error() && { return std::move(error_); } const Error&& error() const&& { return std::move(error_); } private: Error error_; }; template < class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable::value)> inline bool operator==( const Unexpected& lhs, const Unexpected& rhs) { return lhs.error() == rhs.error(); } template < class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable::value)> inline bool operator!=( const Unexpected& lhs, const Unexpected& rhs) { return !(lhs == rhs); } /** * For constructing an Unexpected object from an error code. Unexpected objects * are implicitly convertible to Expected object in the error state. Usage is * as follows: * * enum class MyErrorCode { BAD_ERROR, WORSE_ERROR }; * Expected myAPI() { * int i = // ...; * return i ? makeExpected(i) * : makeUnexpected(MyErrorCode::BAD_ERROR); * } */ template FOLLY_NODISCARD constexpr Unexpected::type> makeUnexpected(Error&& err) { return Unexpected::type>{ static_cast(err)}; } template class FOLLY_EXPORT BadExpectedAccess; /** * A common base type for exceptions thrown by Expected when the caller * erroneously requests a value. */ template <> class FOLLY_EXPORT BadExpectedAccess : public std::exception { public: explicit BadExpectedAccess() noexcept = default; BadExpectedAccess(BadExpectedAccess const&) {} BadExpectedAccess& operator=(BadExpectedAccess const&) { return *this; } char const* what() const noexcept override { return "bad expected access"; } }; /** * An exception type thrown by Expected on catastrophic logic errors, i.e., when * the caller tries to access the value within an Expected but when the Expected * instead contains an error. */ template class FOLLY_EXPORT BadExpectedAccess : public BadExpectedAccess { public: explicit BadExpectedAccess(Error error) : error_{static_cast(error)} {} /** * The error code that was held by the Expected object when the caller * erroneously requested the value. */ Error& error() & { return error_; } Error const& error() const& { return error_; } Error&& error() && { return static_cast(error_); } Error const&& error() const&& { return static_cast(error_); } private: Error error_; }; /** * Forward declarations */ template class Expected; template FOLLY_NODISCARD constexpr Expected::type, Error> makeExpected(Value&&); /** * Alias for an Expected type's associated value_type */ template using ExpectedValueType = typename std::remove_reference::type::value_type; /** * Alias for an Expected type's associated error_type */ template using ExpectedErrorType = typename std::remove_reference::type::error_type; // Details... namespace expected_detail { template struct Promise; template struct PromiseReturn; template