Move to std::expected (#1288)

Fixes #1173
This commit is contained in:
Alex Kremer
2024-04-08 16:13:33 +01:00
committed by GitHub
parent dade122c6e
commit 6ff6956a53
40 changed files with 140 additions and 430 deletions

View File

@@ -1,3 +1,6 @@
CompileFlags:
Add: [-D__cpp_concepts=202002]
Diagnostics:
UnusedIncludes: Strict
MissingIncludes: Strict

View File

@@ -19,9 +19,8 @@
#pragma once
#include "util/Expected.hpp"
#include <cstdint>
#include <expected>
namespace data::cassandra {
@@ -59,8 +58,8 @@ struct Limit {
class Handle;
class CassandraError;
using MaybeError = util::Expected<void, CassandraError>;
using ResultOrError = util::Expected<Result, CassandraError>;
using Error = util::Unexpected<CassandraError>;
using MaybeError = std::expected<void, CassandraError>;
using ResultOrError = std::expected<Result, CassandraError>;
using Error = std::unexpected<CassandraError>;
} // namespace data::cassandra

View File

@@ -23,10 +23,10 @@
#include "data/cassandra/Types.hpp"
#include "data/cassandra/impl/ManagedObject.hpp"
#include "data/cassandra/impl/Statement.hpp"
#include "util/Expected.hpp"
#include <cassandra.h>
#include <expected>
#include <stdexcept>
#include <vector>

View File

@@ -20,7 +20,6 @@
#include "etl/impl/SubscriptionSource.hpp"
#include "rpc/JS.hpp"
#include "util/Expected.hpp"
#include "util/Retry.hpp"
#include "util/log/Logger.hpp"
#include "util/requests/Types.hpp"
@@ -42,6 +41,7 @@
#include <chrono>
#include <cstdint>
#include <exception>
#include <expected>
#include <future>
#include <memory>
#include <optional>

View File

@@ -23,7 +23,6 @@
#include "rpc/Errors.hpp"
#include "rpc/common/APIVersion.hpp"
#include "rpc/common/Types.hpp"
#include "util/Expected.hpp"
#include "util/Taggable.hpp"
#include "web/Context.hpp"
@@ -34,6 +33,7 @@
#include <boost/json/value_to.hpp>
#include <ripple/protocol/ErrorCodes.h>
#include <expected>
#include <functional>
#include <memory>
#include <string>
@@ -43,7 +43,7 @@ using namespace util;
namespace rpc {
util::Expected<web::Context, Status>
std::expected<web::Context, Status>
make_WsContext(
boost::asio::yield_context yc,
boost::json::object const& request,
@@ -72,7 +72,7 @@ make_WsContext(
return web::Context(yc, command, *apiVersion, request, session, tagFactory, range, clientIp, session->isAdmin());
}
Expected<web::Context, Status>
std::expected<web::Context, Status>
make_HttpContext(
boost::asio::yield_context yc,
boost::json::object const& request,

View File

@@ -22,7 +22,6 @@
#include "data/Types.hpp"
#include "rpc/Errors.hpp"
#include "rpc/common/APIVersion.hpp"
#include "util/Expected.hpp"
#include "util/Taggable.hpp"
#include "web/Context.hpp"
#include "web/interface/ConnectionBase.hpp"
@@ -31,6 +30,7 @@
#include <boost/json.hpp>
#include <boost/json/object.hpp>
#include <expected>
#include <functional>
#include <memory>
#include <string>
@@ -56,7 +56,7 @@ namespace rpc {
* @param apiVersionParser A parser that is used to parse out the "api_version" field
* @return A Websocket context or error Status
*/
util::Expected<web::Context, Status>
std::expected<web::Context, Status>
make_WsContext(
boost::asio::yield_context yc,
boost::json::object const& request,
@@ -79,7 +79,7 @@ make_WsContext(
* @param isAdmin Whether the connection has admin privileges
* @return A HTTP context or error Status
*/
util::Expected<web::Context, Status>
std::expected<web::Context, Status>
make_HttpContext(
boost::asio::yield_context yc,
boost::json::object const& request,

View File

@@ -58,6 +58,7 @@
#include <ripple/protocol/STObject.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/Seed.h>
#include <ripple/protocol/TxMeta.h>
#include <ripple/protocol/UintTypes.h>

View File

@@ -19,13 +19,11 @@
#pragma once
#include "util/Expected.hpp"
#include <boost/json.hpp>
#include <boost/json/object.hpp>
#include <cstdint>
#include <string>
#include <expected>
namespace rpc {
@@ -60,7 +58,7 @@ public:
* @param request A JSON object representing the request
* @return The specified API version if contained in the JSON object; error string otherwise
*/
util::Expected<uint32_t, std::string> virtual parse(boost::json::object const& request) const = 0;
std::expected<uint32_t, std::string> virtual parse(boost::json::object const& request) const = 0;
};
} // namespace rpc

View File

@@ -30,6 +30,8 @@
namespace rpc {
struct RpcSpec;
/**
* @brief Specifies what a requirement used with @ref rpc::FieldSpec must provide.
*/
@@ -83,7 +85,7 @@ template <typename T>
concept SomeHandlerWithInput = requires(T a, uint32_t version) {
{
a.spec(version)
} -> std::same_as<RpcSpecConstRef>;
} -> std::same_as<RpcSpec const&>;
} and SomeContextProcessWithInput<T> and boost::json::has_value_to<typename T::Input>::value;
/**

View File

@@ -103,4 +103,9 @@ private:
std::vector<FieldSpec> fields_;
};
/**
* @brief An alias for a const reference to @ref RpcSpec.
*/
using RpcSpecConstRef = RpcSpec const&;
} // namespace rpc

View File

@@ -20,7 +20,6 @@
#pragma once
#include "rpc/Errors.hpp"
#include "util/Expected.hpp"
#include <boost/asio/spawn.hpp>
#include <boost/json/conversion.hpp>
@@ -31,6 +30,7 @@
#include <ripple/basics/strHex.h>
#include <cstdint>
#include <expected>
#include <memory>
#include <string>
#include <variant>
@@ -48,35 +48,28 @@ class SubscriptionManager;
namespace rpc {
class Counters;
struct RpcSpec;
struct FieldSpec;
/**
* @brief Return type used for Validators that can return error but don't have
* specific value to return
*/
using MaybeError = util::Expected<void, Status>;
using MaybeError = std::expected<void, Status>;
/**
* @brief The type that represents just the error part of @ref MaybeError
*/
using Error = util::Unexpected<Status>;
using Error = std::unexpected<Status>;
/**
* @brief Return type for each individual handler
*/
template <typename OutputType>
using HandlerReturnType = util::Expected<OutputType, Status>;
using HandlerReturnType = std::expected<OutputType, Status>;
/**
* @brief The final return type out of RPC engine
*/
using ReturnType = util::Expected<boost::json::value, Status>;
/**
* @brief An alias for a const reference to @ref RpcSpec.
*/
using RpcSpecConstRef = RpcSpec const&;
using ReturnType = std::expected<boost::json::value, Status>;
/**
* @brief An empty type used as Output for handlers than don't actually produce output.

View File

@@ -20,13 +20,13 @@
#include "rpc/common/impl/APIVersionParser.hpp"
#include "rpc/common/APIVersion.hpp"
#include "util/Expected.hpp"
#include "util/log/Logger.hpp"
#include <boost/json/object.hpp>
#include <fmt/core.h>
#include <cstdint>
#include <expected>
#include <string>
using namespace std;
@@ -42,10 +42,10 @@ ProductionAPIVersionParser::ProductionAPIVersionParser(util::Config const& confi
{
}
util::Expected<uint32_t, std::string>
std::expected<uint32_t, std::string>
ProductionAPIVersionParser::parse(boost::json::object const& request) const
{
using Error = util::Unexpected<std::string>;
using Error = std::unexpected<std::string>;
if (request.contains("api_version")) {
if (!request.at("api_version").is_int64())

View File

@@ -20,7 +20,6 @@
#pragma once
#include "rpc/common/APIVersion.hpp"
#include "util/Expected.hpp"
#include "util/config/Config.hpp"
#include "util/log/Logger.hpp"
@@ -28,6 +27,7 @@
#include <algorithm>
#include <cstdint>
#include <expected>
#include <string>
namespace rpc::impl {
@@ -74,7 +74,7 @@ public:
ProductionAPIVersionParser(util::Config const& config);
util::Expected<uint32_t, std::string>
std::expected<uint32_t, std::string>
parse(boost::json::object const& request) const override;
inline uint32_t

View File

@@ -112,7 +112,7 @@ ProductionHandlerProvider::ProductionHandlerProvider(
bool
ProductionHandlerProvider::contains(std::string const& command) const
{
return handlerMap_.contains(command); // updated on 4 mar 2024
return handlerMap_.contains(command);
}
std::optional<AnyHandler>

View File

@@ -20,7 +20,6 @@
#pragma once
#include "rpc/common/Concepts.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include <boost/json/value.hpp>

View File

@@ -25,8 +25,6 @@
#include "rpc/JS.hpp"
#include "rpc/RPCHelpers.hpp"
#include "rpc/common/MetaProcessors.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
#include <boost/json/array.hpp>

View File

@@ -20,7 +20,7 @@
#pragma once
#include "data/BackendInterface.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Specs.hpp"
#include <boost/json/array.hpp>
#include <boost/json/conversion.hpp>

View File

@@ -1,286 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2023, the clio developers.
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
/*
* NOTE:
*
* This entire file is taken from rippled and modified slightly to fit this
* codebase as well as fixing the original issue that made this necessary.
*
* The reason is that currently there is no easy way to injest the fix that is
* required to make this implementation correctly work with boost::json::value.
* Since this will be replaced by `std::expected` as soon as possible there is
* not much harm done in doing it this way.
*/
#pragma once
#include "util/Assert.hpp"
#include <boost/outcome.hpp>
#include <boost/outcome/policy/base.hpp>
#include <boost/outcome/result.hpp>
#include <boost/outcome/success_failure.hpp>
#include <ripple/basics/contract.h>
#include <cstddef>
#include <stdexcept>
#include <type_traits>
namespace util {
/** Expected is an approximation of std::expected (hoped for in C++23)
See: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
The implementation is entirely based on boost::outcome_v2::result.
*/
// Documentation is not needed - will be removed as soon as `std::expected` available
/** @cond */
// Exception thrown by an invalid access to Expected.
struct bad_expected_access : public std::runtime_error {
bad_expected_access() : runtime_error("bad expected access")
{
}
};
namespace impl {
// Custom policy for Expected. Always throw on an invalid access.
struct throw_policy : public boost::outcome_v2::policy::base {
template <typename Impl>
static constexpr void
wide_value_check(Impl&& self)
{
if (!base::_has_value(std::forward<Impl>(self)))
ripple::Throw<bad_expected_access>();
}
template <typename Impl>
static constexpr void
wide_error_check(Impl&& self)
{
if (!base::_has_error(std::forward<Impl>(self)))
ripple::Throw<bad_expected_access>();
}
template <typename Impl>
static constexpr void
wide_exception_check(Impl&& self)
{
if (!base::_has_exception(std::forward<Impl>(self)))
ripple::Throw<bad_expected_access>();
}
};
} // namespace impl
// Definition of Unexpected, which is used to construct the unexpected
// return type of an Expected.
template <typename E>
class Unexpected {
public:
static_assert(!std::is_same_v<E, void>, "E must not be void");
Unexpected() = delete;
constexpr explicit Unexpected(E const& e) : val_(e)
{
}
constexpr explicit Unexpected(E&& e) : val_(std::move(e))
{
}
constexpr E const&
value() const&
{
return val_;
}
constexpr E&
value() &
{
return val_;
}
constexpr E&&
value() &&
{
return std::move(val_);
}
constexpr E const&&
value() const&&
{
return std::move(val_);
}
private:
E val_;
};
// Unexpected deduction guide that converts array to const*.
template <typename E, std::size_t N>
Unexpected(E (&)[N]) -> Unexpected<E const*>;
// Definition of Expected. All of the machinery comes from boost::result.
template <typename T, typename E>
class Expected : private boost::outcome_v2::result<T, E, impl::throw_policy> {
using Base = boost::outcome_v2::result<T, E, impl::throw_policy>;
public:
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, T>>>
constexpr Expected(U r) : Base(T(std::forward<U>(r)))
{
}
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, E>>>
constexpr Expected(Unexpected<U> e) : Base(E(std::forward<U>(e.value())))
{
}
constexpr bool
has_value() const
{
return Base::has_value();
}
constexpr T const&
value() const&
{
return Base::value();
}
constexpr T&
value() &
{
return Base::value();
}
constexpr T
value() &&
{
return std::move(*base()).value();
}
constexpr E const&
error() const&
{
return Base::error();
}
constexpr E&
error() &
{
return Base::error();
}
constexpr E
error() &&
{
return std::move(*base()).error();
}
constexpr explicit
operator bool() const
{
return has_value();
}
// Add operator* and operator-> so the Expected API looks a bit more like
// what std::expected is likely to look like. See:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
[[nodiscard]] constexpr T&
operator*()
{
return this->value();
}
[[nodiscard]] constexpr T const&
operator*() const
{
return this->value();
}
[[nodiscard]] constexpr T*
operator->()
{
return &this->value();
}
[[nodiscard]] constexpr T const*
operator->() const
{
return &this->value();
}
private:
Base*
base()
{
auto b = dynamic_cast<Base*>(this);
ASSERT(b != nullptr, "Base class is not Base");
return b;
}
};
// Specialization of Expected<void, E>. Allows returning either success
// (without a value) or the reason for the failure.
template <typename E>
class [[nodiscard]] Expected<void, E> : private boost::outcome_v2::result<void, E, impl::throw_policy> {
using Base = boost::outcome_v2::result<void, E, impl::throw_policy>;
public:
// The default constructor makes a successful Expected<void, E>.
// This aligns with std::expected behavior proposed in P0323R10.
constexpr Expected() : Base(boost::outcome_v2::success())
{
}
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, E>>>
constexpr Expected(Unexpected<U> e) : Base(E(std::forward<U>(e.value())))
{
}
constexpr E const&
error() const
{
return Base::error();
}
constexpr E&
error()
{
return Base::error();
}
constexpr explicit
operator bool() const
{
return Base::has_value();
}
};
/** @endcond */
} // namespace util

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/async/Concepts.hpp"
#include "util/async/Error.hpp"
#include "util/async/impl/Any.hpp"
@@ -29,6 +28,7 @@
#include <fmt/std.h>
#include <any>
#include <expected>
#include <thread>
#include <type_traits>
#include <utility>
@@ -95,13 +95,13 @@ public:
*
* @return The result of the operation
*/
[[nodiscard]] util::Expected<RetType, ExecutionError>
[[nodiscard]] std::expected<RetType, ExecutionError>
get()
{
try {
auto data = operation_.get();
if (not data)
return util::Unexpected(std::move(data).error());
return std::unexpected(std::move(data).error());
if constexpr (std::is_void_v<RetType>) {
return {};
@@ -110,7 +110,7 @@ public:
}
} catch (std::bad_any_cast const& e) {
return util::Unexpected{ExecutionError(fmt::format("{}", std::this_thread::get_id()), "Bad any cast")};
return std::unexpected{ExecutionError(fmt::format("{}", std::this_thread::get_id()), "Bad any cast")};
}
}

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/async/Concepts.hpp"
#include "util/async/Error.hpp"
#include "util/async/Operation.hpp"
@@ -38,6 +37,7 @@
#include <chrono>
#include <cstddef>
#include <expected>
#include <optional>
#include <type_traits>
#include <utility>
@@ -82,9 +82,9 @@ struct AsioPoolContext {
* @brief A highly configurable execution context.
*
* This execution context is used as the base for all specialized execution contexts.
* Return values are handled by capturing them and returning them packaged as util::Expected.
* Return values are handled by capturing them and returning them packaged as std::expected.
* Exceptions may or may not be caught and handled depending on the error strategy. The default behavior is to catch and
* package them as the error channel of util::Expected.
* package them as the error channel of std::expected.
*/
template <
typename ContextType,
@@ -108,7 +108,7 @@ public:
using ExecutorType = typename ContextHolderType::Executor;
template <typename T>
using ValueType = util::Expected<T, ExecutionError>;
using ValueType = std::expected<T, ExecutionError>;
using StopSource = StopSourceType;

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/async/Concepts.hpp"
#include "util/async/Error.hpp"
#include "util/async/context/impl/Timer.hpp"
@@ -28,6 +27,7 @@
#include <boost/asio/strand.hpp>
#include <boost/asio/thread_pool.hpp>
#include <expected>
#include <optional>
namespace util::async::impl {
@@ -62,12 +62,12 @@ outcomeForHandler(auto&& fn)
{
if constexpr (SomeHandlerWith<decltype(fn), typename StopSourceType::Token>) {
using FnRetType = decltype(fn(std::declval<typename StopSourceType::Token>()));
using RetType = util::Expected<FnRetType, ExecutionError>;
using RetType = std::expected<FnRetType, ExecutionError>;
return StoppableOutcome<RetType, StopSourceType>();
} else {
using FnRetType = decltype(fn());
using RetType = util::Expected<FnRetType, ExecutionError>;
using RetType = std::expected<FnRetType, ExecutionError>;
return Outcome<RetType>();
}

View File

@@ -22,10 +22,8 @@
#include <any>
#include <type_traits>
// Note: This is a workaround for util::Expected. This is not needed when using std::expected.
// Will be removed after the migration to std::expected is complete (#1173)
// Issue to track this removal can be found here: https://github.com/XRPLF/clio/issues/1174
namespace util::async::impl {
/**

View File

@@ -20,11 +20,11 @@
#pragma once
#include "util/Assert.hpp"
#include "util/Expected.hpp"
#include "util/async/Concepts.hpp"
#include "util/async/Error.hpp"
#include "util/async/impl/Any.hpp"
#include <expected>
#include <memory>
#include <type_traits>
@@ -55,7 +55,7 @@ public:
pimpl_->wait();
}
util::Expected<Any, ExecutionError>
std::expected<Any, ExecutionError>
get()
{
return pimpl_->get();
@@ -87,7 +87,7 @@ private:
virtual void
wait() noexcept = 0;
virtual util::Expected<Any, ExecutionError>
virtual std::expected<Any, ExecutionError>
get() = 0;
virtual void
requestStop() = 0;
@@ -111,7 +111,7 @@ private:
return operation.wait();
}
util::Expected<Any, ExecutionError>
std::expected<Any, ExecutionError>
get() override
{
// Note: return type of the operation was already wrapped to impl::Any by AnyExecutionContext

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/async/Concepts.hpp"
#include "util/async/Error.hpp"
@@ -27,6 +26,7 @@
#include <fmt/std.h>
#include <exception>
#include <expected>
#include <thread>
namespace util::async::impl {
@@ -41,11 +41,11 @@ struct DefaultErrorHandler {
fn(outcome, std::forward<Args>(args)...);
} catch (std::exception const& e) {
outcome.setValue(
util::Unexpected(ExecutionError{fmt::format("{}", std::this_thread::get_id()), e.what()})
std::unexpected(ExecutionError{fmt::format("{}", std::this_thread::get_id()), e.what()})
);
} catch (...) {
outcome.setValue(
util::Unexpected(ExecutionError{fmt::format("{}", std::this_thread::get_id()), "unknown"})
std::unexpected(ExecutionError{fmt::format("{}", std::this_thread::get_id()), "unknown"})
);
}
};

View File

@@ -19,7 +19,6 @@
#include "util/requests/RequestBuilder.hpp"
#include "util/Expected.hpp"
#include "util/log/Logger.hpp"
#include "util/requests/Types.hpp"
#include "util/requests/impl/StreamData.hpp"
@@ -41,6 +40,7 @@
#include <openssl/tls1.h>
#include <chrono>
#include <expected>
#include <string>
#include <string_view>
#include <utility>
@@ -97,48 +97,48 @@ RequestBuilder::setTarget(std::string_view target)
return *this;
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::getSsl(boost::asio::yield_context yield)
{
return doSslRequest(yield, http::verb::get);
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::getPlain(boost::asio::yield_context yield)
{
return doPlainRequest(yield, http::verb::get);
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::get(asio::yield_context yield)
{
return doRequest(yield, http::verb::get);
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::postSsl(boost::asio::yield_context yield)
{
return doSslRequest(yield, http::verb::post);
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::postPlain(boost::asio::yield_context yield)
{
return doPlainRequest(yield, http::verb::post);
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::post(asio::yield_context yield)
{
return doRequest(yield, http::verb::post);
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::doSslRequest(asio::yield_context yield, beast::http::verb method)
{
auto streamData = impl::SslTcpStreamData::create(yield);
if (not streamData.has_value())
return Unexpected{std::move(streamData).error()};
return std::unexpected{std::move(streamData).error()};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -146,19 +146,19 @@ RequestBuilder::doSslRequest(asio::yield_context yield, beast::http::verb method
#pragma GCC diagnostic pop
beast::error_code errorCode;
errorCode.assign(static_cast<int>(::ERR_get_error()), asio::error::get_ssl_category());
return Unexpected{RequestError{"SSL setup failed", errorCode}};
return std::unexpected{RequestError{"SSL setup failed", errorCode}};
}
return doRequestImpl(std::move(streamData).value(), yield, method);
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::doPlainRequest(asio::yield_context yield, beast::http::verb method)
{
auto streamData = impl::TcpStreamData{yield};
return doRequestImpl(std::move(streamData), yield, method);
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::doRequest(asio::yield_context yield, beast::http::verb method)
{
auto result = doSslRequest(yield, method);
@@ -179,7 +179,7 @@ RequestBuilder::doRequest(asio::yield_context yield, beast::http::verb method)
* @return Response or error
*/
template <typename StreamDataType>
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
RequestBuilder::doRequestImpl(StreamDataType&& streamData, asio::yield_context yield, http::verb const method)
{
auto executor = asio::get_associated_executor(yield);
@@ -188,14 +188,14 @@ RequestBuilder::doRequestImpl(StreamDataType&& streamData, asio::yield_context y
tcp::resolver resolver(executor);
auto const resolverResult = resolver.async_resolve(host_, port_, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Resolve error", errorCode}};
return std::unexpected{RequestError{"Resolve error", errorCode}};
auto& stream = streamData.stream;
beast::get_lowest_layer(stream).expires_after(timeout_);
beast::get_lowest_layer(stream).async_connect(resolverResult, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Connection error", errorCode}};
return std::unexpected{RequestError{"Connection error", errorCode}};
request_.method(method);
@@ -203,28 +203,28 @@ RequestBuilder::doRequestImpl(StreamDataType&& streamData, asio::yield_context y
beast::get_lowest_layer(stream).expires_after(timeout_);
stream.async_handshake(asio::ssl::stream_base::client, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Handshake error", errorCode}};
return std::unexpected{RequestError{"Handshake error", errorCode}};
}
beast::get_lowest_layer(stream).expires_after(timeout_);
http::async_write(stream, request_, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Write error", errorCode}};
return std::unexpected{RequestError{"Write error", errorCode}};
beast::flat_buffer buffer;
http::response<http::string_body> response;
http::async_read(stream, buffer, response, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Read error", errorCode}};
return std::unexpected{RequestError{"Read error", errorCode}};
if (response.result() != http::status::ok)
return Unexpected{RequestError{"Response status is not OK"}};
return std::unexpected{RequestError{"Response status is not OK"}};
beast::get_lowest_layer(stream).socket().shutdown(tcp::socket::shutdown_both, errorCode);
if (errorCode && errorCode != beast::errc::not_connected)
return Unexpected{RequestError{"Shutdown socket error", errorCode}};
return std::unexpected{RequestError{"Shutdown socket error", errorCode}};
return std::move(response).body();
}

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/log/Logger.hpp"
#include "util/requests/Types.hpp"
@@ -33,6 +32,7 @@
#include <boost/beast/http/verb.hpp>
#include <chrono>
#include <expected>
#include <string>
#include <string_view>
#include <vector>
@@ -116,7 +116,7 @@ public:
* @param yield yield context
* @return Expected response or error
*/
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
getSsl(boost::asio::yield_context yield);
/**
@@ -128,7 +128,7 @@ public:
* @param yield yield context
* @return Expected response or error
*/
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
getPlain(boost::asio::yield_context yield);
/**
@@ -141,7 +141,7 @@ public:
* @param yield yield context
* @return Expected response or error
*/
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
get(boost::asio::yield_context yield);
/**
@@ -153,7 +153,7 @@ public:
* @param yield yield context
* @return Expected response or error
*/
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
postSsl(boost::asio::yield_context yield);
/**
@@ -165,7 +165,7 @@ public:
* @param yield yield context
* @return Expected response or error
*/
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
postPlain(boost::asio::yield_context yield);
/**
@@ -178,23 +178,23 @@ public:
* @param yield yield context
* @return Expected response or error
*/
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
post(boost::asio::yield_context yield);
static constexpr std::chrono::milliseconds DEFAULT_TIMEOUT{30000}; /**< Default timeout for requests */
private:
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
doSslRequest(boost::asio::yield_context yield, boost::beast::http::verb method);
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
doPlainRequest(boost::asio::yield_context yield, boost::beast::http::verb method);
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
doRequest(boost::asio::yield_context yield, boost::beast::http::verb method);
template <typename StreamDataType>
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
doRequestImpl(StreamDataType&& streamData, boost::asio::yield_context yield, boost::beast::http::verb method);
};

View File

@@ -19,7 +19,6 @@
#include "util/requests/WsConnection.hpp"
#include "util/Expected.hpp"
#include "util/log/Logger.hpp"
#include "util/requests/Types.hpp"
#include "util/requests/impl/StreamData.hpp"
@@ -41,6 +40,7 @@
#include <openssl/tls1.h>
#include <chrono>
#include <expected>
#include <iterator>
#include <string>
#include <utility>
@@ -92,12 +92,12 @@ WsConnectionBuilder::setWsHandshakeTimeout(std::chrono::steady_clock::duration t
return *this;
}
Expected<WsConnectionPtr, RequestError>
std::expected<WsConnectionPtr, RequestError>
WsConnectionBuilder::sslConnect(asio::yield_context yield) const
{
auto streamData = impl::SslWsStreamData::create(yield);
if (not streamData.has_value())
return Unexpected{std::move(streamData).error()};
return std::unexpected{std::move(streamData).error()};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -105,18 +105,18 @@ WsConnectionBuilder::sslConnect(asio::yield_context yield) const
#pragma GCC diagnostic pop
beast::error_code errorCode;
errorCode.assign(static_cast<int>(::ERR_get_error()), beast::net::error::get_ssl_category());
return Unexpected{RequestError{"SSL setup failed", errorCode}};
return std::unexpected{RequestError{"SSL setup failed", errorCode}};
}
return connectImpl(std::move(streamData).value(), yield);
}
Expected<WsConnectionPtr, RequestError>
std::expected<WsConnectionPtr, RequestError>
WsConnectionBuilder::plainConnect(asio::yield_context yield) const
{
return connectImpl(impl::WsStreamData{yield}, yield);
}
Expected<WsConnectionPtr, RequestError>
std::expected<WsConnectionPtr, RequestError>
WsConnectionBuilder::connect(asio::yield_context yield) const
{
auto sslConnection = sslConnect(yield);
@@ -138,7 +138,7 @@ WsConnectionBuilder::connect(asio::yield_context yield) const
* @return WebSocket connection or error
*/
template <typename StreamDataType>
Expected<WsConnectionPtr, RequestError>
std::expected<WsConnectionPtr, RequestError>
WsConnectionBuilder::connectImpl(StreamDataType&& streamData, asio::yield_context yield) const
{
auto context = asio::get_associated_executor(yield);
@@ -147,20 +147,20 @@ WsConnectionBuilder::connectImpl(StreamDataType&& streamData, asio::yield_contex
asio::ip::tcp::resolver resolver(context);
auto const results = resolver.async_resolve(host_, port_, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Resolve error", errorCode}};
return std::unexpected{RequestError{"Resolve error", errorCode}};
auto& ws = streamData.stream;
beast::get_lowest_layer(ws).expires_after(connectionTimeout_);
auto endpoint = beast::get_lowest_layer(ws).async_connect(results, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Connect error", errorCode}};
return std::unexpected{RequestError{"Connect error", errorCode}};
if constexpr (StreamDataType::sslEnabled) {
beast::get_lowest_layer(ws).expires_after(connectionTimeout_);
ws.next_layer().async_handshake(asio::ssl::stream_base::client, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"SSL handshake error", errorCode}};
return std::unexpected{RequestError{"SSL handshake error", errorCode}};
}
// Turn off the timeout on the tcp_stream, because the websocket stream has its own timeout system
@@ -177,7 +177,7 @@ WsConnectionBuilder::connectImpl(StreamDataType&& streamData, asio::yield_contex
std::string const host = fmt::format("{}:{}", host_, endpoint.port());
ws.async_handshake(host, target_, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Handshake error", errorCode}};
return std::unexpected{RequestError{"Handshake error", errorCode}};
if constexpr (StreamDataType::sslEnabled) {
return std::make_unique<impl::SslWsConnection>(std::move(ws));

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/log/Logger.hpp"
#include "util/requests/Types.hpp"
@@ -32,6 +31,7 @@
#include <boost/beast/websocket/stream.hpp>
#include <chrono>
#include <expected>
#include <memory>
#include <optional>
#include <string>
@@ -55,7 +55,7 @@ public:
* @param yield yield context
* @return Message or error
*/
virtual Expected<std::string, RequestError>
virtual std::expected<std::string, RequestError>
read(boost::asio::yield_context yield) = 0;
/**
@@ -154,7 +154,7 @@ public:
* @param yield yield context
* @return WebSocket connection or error
*/
Expected<WsConnectionPtr, RequestError>
std::expected<WsConnectionPtr, RequestError>
sslConnect(boost::asio::yield_context yield) const;
/**
@@ -163,7 +163,7 @@ public:
* @param yield yield context
* @return WebSocket connection or error
*/
Expected<WsConnectionPtr, RequestError>
std::expected<WsConnectionPtr, RequestError>
plainConnect(boost::asio::yield_context yield) const;
/**
@@ -172,14 +172,14 @@ public:
* @param yield yield context
* @return WebSocket connection or error
*/
Expected<WsConnectionPtr, RequestError>
std::expected<WsConnectionPtr, RequestError>
connect(boost::asio::yield_context yield) const;
static constexpr std::chrono::seconds DEFAULT_TIMEOUT{5}; /**< Default timeout for connecting */
private:
template <typename StreamDataType>
Expected<WsConnectionPtr, RequestError>
std::expected<WsConnectionPtr, RequestError>
connectImpl(StreamDataType&& streamData, boost::asio::yield_context yield) const;
};

View File

@@ -19,7 +19,6 @@
#include "util/requests/impl/SslContext.hpp"
#include "util/Expected.hpp"
#include "util/requests/Types.hpp"
#include <boost/asio/buffer.hpp>
@@ -33,6 +32,7 @@
#include <array>
#include <cstddef>
#include <expected>
#include <filesystem>
#include <fstream>
#include <ios>
@@ -62,7 +62,7 @@ constexpr std::array CERT_FILE_PATHS{
"/system/etc/security/cacerts", // Android
};
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
getRootCertificate()
{
for (auto const& path : CERT_FILE_PATHS) {
@@ -76,19 +76,19 @@ getRootCertificate()
return std::move(buffer).str();
}
}
return Unexpected{RequestError{"SSL setup failed: could not find root certificate"}};
return std::unexpected{RequestError{"SSL setup failed: could not find root certificate"}};
}
} // namespace
Expected<boost::asio::ssl::context, RequestError>
std::expected<boost::asio::ssl::context, RequestError>
makeSslContext()
{
ssl::context context{ssl::context::sslv23_client};
context.set_verify_mode(ssl::verify_peer);
auto const rootCertificate = getRootCertificate();
if (not rootCertificate.has_value()) {
return Unexpected{rootCertificate.error()};
return std::unexpected{rootCertificate.error()};
}
context.add_certificate_authority(asio::buffer(rootCertificate->data(), rootCertificate->size()));
return context;

View File

@@ -19,18 +19,18 @@
#pragma once
#include "util/Expected.hpp"
#include "util/requests/Types.hpp"
#include <boost/asio/ssl/context.hpp>
#include <boost/beast/core/error.hpp>
#include <expected>
#include <optional>
#include <string>
namespace util::requests::impl {
Expected<boost::asio::ssl::context, RequestError>
std::expected<boost::asio::ssl::context, RequestError>
makeSslContext();
std::optional<std::string>

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/requests/Types.hpp"
#include "util/requests/impl/SslContext.hpp"
@@ -33,6 +32,7 @@
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/stream.hpp>
#include <expected>
#include <utility>
namespace util::requests::impl {
@@ -58,12 +58,12 @@ class SslStreamData {
public:
static constexpr bool sslEnabled = true;
static Expected<SslStreamData, RequestError>
static std::expected<SslStreamData, RequestError>
create(boost::asio::yield_context yield)
{
auto sslContext = makeSslContext();
if (not sslContext.has_value()) {
return Unexpected{std::move(sslContext.error())};
return std::unexpected{std::move(sslContext.error())};
}
return SslStreamData{std::move(sslContext).value(), yield};
}

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/requests/Types.hpp"
#include "util/requests/WsConnection.hpp"
@@ -35,6 +34,7 @@
#include <boost/beast/websocket/stream_base.hpp>
#include <chrono>
#include <expected>
#include <optional>
#include <string>
#include <utility>
@@ -50,7 +50,7 @@ public:
{
}
Expected<std::string, RequestError>
std::expected<std::string, RequestError>
read(boost::asio::yield_context yield) override
{
boost::beast::error_code errorCode;
@@ -59,7 +59,7 @@ public:
ws_.async_read(buffer, yield[errorCode]);
if (errorCode)
return Unexpected{RequestError{"Read error", errorCode}};
return std::unexpected{RequestError{"Read error", errorCode}};
return boost::beast::buffers_to_string(std::move(buffer).data());
}

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/MockOperation.hpp"
#include "util/MockStopToken.hpp"
#include "util/MockStrand.hpp"
@@ -30,12 +29,13 @@
#include <gmock/gmock.h>
#include <chrono>
#include <expected>
#include <functional>
#include <optional>
struct MockExecutionContext {
template <typename T>
using ValueType = util::Expected<T, util::async::ExecutionError>;
using ValueType = std::expected<T, util::async::ExecutionError>;
using StopSource = MockStopSource;
using StopToken = MockStopToken;

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/MockOperation.hpp"
#include "util/async/AnyStopToken.hpp"
#include "util/async/Error.hpp"
@@ -28,12 +27,13 @@
#include <gmock/gmock.h>
#include <chrono>
#include <expected>
#include <functional>
#include <optional>
struct MockStrand {
template <typename T>
using ValueType = util::Expected<T, util::async::ExecutionError>;
using ValueType = std::expected<T, util::async::ExecutionError>;
template <typename T>
using Operation = MockOperation<T>;

View File

@@ -19,7 +19,6 @@
#include "util/TestWsServer.hpp"
#include "util/Expected.hpp"
#include "util/requests/Types.hpp"
#include <boost/asio/buffer.hpp>
@@ -38,6 +37,7 @@
#include <boost/beast/websocket/stream_base.hpp>
#include <gtest/gtest.h>
#include <expected>
#include <optional>
#include <string>
#include <utility>
@@ -91,7 +91,7 @@ TestWsServer::TestWsServer(asio::io_context& context, std::string const& host, i
acceptor_.bind(endpoint);
}
util::Expected<TestWsConnection, util::requests::RequestError>
std::expected<TestWsConnection, util::requests::RequestError>
TestWsServer::acceptConnection(asio::yield_context yield)
{
acceptor_.listen(asio::socket_base::max_listen_connections);
@@ -100,13 +100,13 @@ TestWsServer::acceptConnection(asio::yield_context yield)
asio::ip::tcp::socket socket(acceptor_.get_executor());
acceptor_.async_accept(socket, yield[errorCode]);
if (errorCode)
return util::Unexpected{util::requests::RequestError{"Accept error", errorCode}};
return std::unexpected{util::requests::RequestError{"Accept error", errorCode}};
boost::beast::websocket::stream<boost::beast::tcp_stream> ws(std::move(socket));
ws.set_option(websocket::stream_base::timeout::suggested(boost::beast::role_type::server));
ws.async_accept(yield[errorCode]);
if (errorCode)
return util::Unexpected{util::requests::RequestError{"Handshake error", errorCode}};
return std::unexpected{util::requests::RequestError{"Handshake error", errorCode}};
return TestWsConnection(std::move(ws));
}

View File

@@ -19,7 +19,6 @@
#pragma once
#include "util/Expected.hpp"
#include "util/requests/Types.hpp"
#include <boost/asio/io_context.hpp>
@@ -28,6 +27,7 @@
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/beast/websocket/stream.hpp>
#include <expected>
#include <functional>
#include <optional>
#include <string>
@@ -59,7 +59,7 @@ class TestWsServer {
public:
TestWsServer(boost::asio::io_context& context, std::string const& host, int port);
util::Expected<TestWsConnection, util::requests::RequestError>
std::expected<TestWsConnection, util::requests::RequestError>
acceptConnection(boost::asio::yield_context yield);
void

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include "util/Expected.hpp"
#include "util/MockOperation.hpp"
#include "util/async/AnyOperation.hpp"
#include "util/async/Error.hpp"
@@ -26,14 +25,15 @@
#include <gtest/gtest.h>
#include <any>
#include <expected>
#include <string>
using namespace util::async;
using namespace ::testing;
struct AnyOperationTests : Test {
using OperationType = MockOperation<util::Expected<impl::Any, ExecutionError>>;
using ScheduledOperationType = MockScheduledOperation<util::Expected<impl::Any, ExecutionError>>;
using OperationType = MockOperation<std::expected<impl::Any, ExecutionError>>;
using ScheduledOperationType = MockScheduledOperation<std::expected<impl::Any, ExecutionError>>;
NaggyMock<OperationType> mockOp;
NaggyMock<ScheduledOperationType> mockScheduledOp;
@@ -46,7 +46,7 @@ using AnyOperationDeathTest = AnyOperationTests;
TEST_F(AnyOperationTests, VoidDataYieldsNoError)
{
auto const noError = util::Expected<impl::Any, ExecutionError>(impl::Any{});
auto const noError = std::expected<impl::Any, ExecutionError>(impl::Any{});
EXPECT_CALL(mockOp, get()).WillOnce(Return(noError));
auto res = voidOp.get();
ASSERT_TRUE(res);
@@ -85,7 +85,7 @@ TEST_F(AnyOperationTests, RequestStopCallPropagated)
TEST_F(AnyOperationTests, GetPropagatesError)
{
EXPECT_CALL(mockOp, get()).WillOnce(Return(util::Unexpected(ExecutionError{"tid", "Not good"})));
EXPECT_CALL(mockOp, get()).WillOnce(Return(std::unexpected(ExecutionError{"tid", "Not good"})));
auto res = intOp.get();
ASSERT_FALSE(res);
EXPECT_TRUE(res.error().message.ends_with("Not good"));

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include "util/Expected.hpp"
#include "util/MockOperation.hpp"
#include "util/MockStrand.hpp"
#include "util/async/AnyOperation.hpp"
@@ -29,6 +28,7 @@
#include <any>
#include <chrono>
#include <expected>
#include <functional>
#include <type_traits>

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include "util/Expected.hpp"
#include "util/Fixtures.hpp"
#include "util/TestHttpServer.hpp"
#include "util/requests/RequestBuilder.hpp"
@@ -32,6 +31,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <expected>
#include <optional>
#include <string>
#include <thread>
@@ -111,14 +111,14 @@ TEST_P(RequestBuilderTest, SimpleRequest)
);
runSpawn([this, replyBody](asio::yield_context yield) {
auto const response = [&]() -> util::Expected<std::string, RequestError> {
auto const response = [&]() -> std::expected<std::string, RequestError> {
switch (GetParam().method) {
case http::verb::get:
return builder.getPlain(yield);
case http::verb::post:
return builder.postPlain(yield);
default:
return util::Unexpected{RequestError{"Invalid HTTP verb"}};
return std::unexpected{RequestError{"Invalid HTTP verb"}};
}
}();
ASSERT_TRUE(response) << response.error().message();
@@ -243,14 +243,14 @@ TEST_P(RequestBuilderSslTest, TrySslUsePlain)
);
runSpawn([this](asio::yield_context yield) {
auto const response = [&]() -> util::Expected<std::string, RequestError> {
auto const response = [&]() -> std::expected<std::string, RequestError> {
switch (GetParam().method) {
case http::verb::get:
return builder.get(yield);
case http::verb::post:
return builder.post(yield);
default:
return util::Unexpected{RequestError{"Invalid HTTP verb"}};
return std::unexpected{RequestError{"Invalid HTTP verb"}};
}
}();
ASSERT_TRUE(response) << response.error().message();

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include "util/Expected.hpp"
#include "util/Fixtures.hpp"
#include "util/TestWsServer.hpp"
#include "util/requests/Types.hpp"
@@ -29,6 +28,7 @@
#include <chrono>
#include <cstddef>
#include <expected>
#include <optional>
#include <string>
#include <thread>
@@ -44,7 +44,7 @@ struct WsConnectionTestsBase : SyncAsioContextTest {
template <typename T, typename E>
T
unwrap(util::Expected<T, E> expected)
unwrap(std::expected<T, E> expected)
{
[&]() { ASSERT_TRUE(expected.has_value()) << expected.error().message(); }();
return std::move(expected).value();