From 2aa4a82499d4becd2284cdb482213d541b8804dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 16:29:10 +0200 Subject: Adding upstream version 86.0.1. Signed-off-by: Daniel Baumann --- mfbt/ResultExtensions.h | 334 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 mfbt/ResultExtensions.h (limited to 'mfbt/ResultExtensions.h') diff --git a/mfbt/ResultExtensions.h b/mfbt/ResultExtensions.h new file mode 100644 index 0000000000..7e15e65256 --- /dev/null +++ b/mfbt/ResultExtensions.h @@ -0,0 +1,334 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Extensions to the Result type to enable simpler handling of XPCOM/NSPR + * results. */ + +#ifndef mozilla_ResultExtensions_h +#define mozilla_ResultExtensions_h + +#include "mozilla/Assertions.h" +#include "nscore.h" +#include "prtypes.h" + +namespace mozilla { + +// Allow nsresult errors to automatically convert to nsresult values, so MOZ_TRY +// can be used in XPCOM methods with Result results. +template <> +class MOZ_MUST_USE_TYPE GenericErrorResult { + nsresult mErrorValue; + + template + friend class Result; + + public: + explicit GenericErrorResult(nsresult aErrorValue) : mErrorValue(aErrorValue) { + MOZ_ASSERT(NS_FAILED(aErrorValue)); + } + + operator nsresult() const { return mErrorValue; } +}; + +// Allow MOZ_TRY to handle `PRStatus` values. +inline Result ToResult(PRStatus aValue); + +} // namespace mozilla + +#include "mozilla/Result.h" + +namespace mozilla { + +inline Result ToResult(nsresult aValue) { + if (NS_FAILED(aValue)) { + return Err(aValue); + } + return Ok(); +} + +inline Result ToResult(PRStatus aValue) { + if (aValue == PR_SUCCESS) { + return Ok(); + } + return Err(NS_ERROR_FAILURE); +} + +namespace detail { +template +auto ResultRefAsParam(R& aResult) { + return &aResult; +} + +template +Result ToResultInvokeInternal(const Func& aFunc, + const RArgMapper& aRArgMapper, + Args&&... aArgs) { + // XXX Thereotically, if R is a pointer to a non-refcounted type, this might + // be a non-owning pointer, but unless we find a case where this actually is + // relevant, it's safe to forbid any raw pointer result. + static_assert( + !std::is_pointer_v, + "Raw pointer results are not supported, please specify a smart pointer " + "result type explicitly, so that getter_AddRefs is used"); + + R res; + nsresult rv = aFunc(std::forward(aArgs)..., aRArgMapper(res)); + if (NS_FAILED(rv)) { + return Err(rv); + } + return res; +} + +template +struct outparam_as_pointer; + +template +struct outparam_as_pointer { + using type = T*; +}; + +template +struct outparam_as_reference; + +template +struct outparam_as_reference { + using type = T&; +}; + +template typename RArg, typename Func, + typename... Args> +using to_result_retval_t = decltype( + std::declval()(std::declval()..., + std::declval()))>::type>()), + Result(Err(NS_ERROR_FAILURE))); + +// There are two ToResultInvokeSelector overloads, which cover the cases of a) a +// pointer-typed output parameter, and b) a reference-typed output parameter, +// using to_result_retval_t in connection with outparam_as_pointer and +// outparam_as_reference type traits. These type traits may be specialized for +// types other than raw pointers to allow calling functions with argument types +// that implicitly convert/bind to a raw pointer/reference. The overload that is +// used is selected by expression SFINAE: the decltype expression in +// to_result_retval_t is only valid in either case. +template +auto ToResultInvokeSelector(const Func& aFunc, Args&&... aArgs) + -> to_result_retval_t { + return ToResultInvokeInternal( + aFunc, [](R& res) -> decltype(auto) { return ResultRefAsParam(res); }, + std::forward(aArgs)...); +} + +template +auto ToResultInvokeSelector(const Func& aFunc, Args&&... aArgs) + -> to_result_retval_t { + return ToResultInvokeInternal( + aFunc, [](R& res) -> decltype(auto) { return *ResultRefAsParam(res); }, + std::forward(aArgs)...); +} + +} // namespace detail + +/** + * Adapts a function with a nsresult error type and an R* output parameter as + * the last parameter to a function returning a mozilla::Result + * object. + * + * This can also be used with member functions together with std::men_fn, e.g. + * + * nsCOMPtr file = ...; + * auto existsOrErr = ToResultInvoke(std::mem_fn(&nsIFile::Exists), + * *file); + * + * but it is more convenient to use the member function overload, which + * has the additional benefit of enabling the deduction of the success result + * type: + * + * nsCOMPtr file = ...; + * auto existsOrErr = ToResultInvoke(*file, &nsIFile::Exists); + */ +template +Result ToResultInvoke(const Func& aFunc, Args&&... aArgs) { + return detail::ToResultInvokeSelector( + aFunc, std::forward(aArgs)...); +} + +namespace detail { +template +struct tag { + using type = T; +}; + +template +struct select_last { + using type = typename decltype((tag{}, ...))::type; +}; + +template +using select_last_t = typename select_last::type; + +template <> +struct select_last<> { + using type = void; +}; + +template +auto ToResultInvokeMemberFunction(T& aObj, const Func& aFunc, Args&&... aArgs) { + if constexpr (std::is_pointer_v || + (std::is_lvalue_reference_v && + !std::is_const_v>)) { + auto lambda = [&](RArg res) { + return (aObj.*aFunc)(std::forward(aArgs)..., res); + }; + return detail::ToResultInvokeSelector< + std::remove_reference_t>, decltype(lambda)>( + lambda); + } else { + // No output parameter present, return a Result + return mozilla::ToResult((aObj.*aFunc)(std::forward(aArgs)...)); + } +} + +// For use in MOZ_TO_RESULT_INVOKE. +template +auto DerefHelper(const T&) -> T&; + +template +auto DerefHelper(T*) -> T&; + +template