diff --git a/.clang-tidy b/.clang-tidy
index a5e47ca..2cf5c3f 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,9 +1,6 @@
# clang-tidy config file
---
-Checks: 'clang-diagnostic-*,clang-analyzer-*,modernize*,performance*,readability-*size*,readability*redundant*,-readability-redundant-member-init,-readability-redundant-access-specifiers,misc*,boost-use-to-string,cert*,google-explicit-constructor,-cert-err58-cpp,-modernize-concat-nested-namespaces,-modernize-use-nodiscard,-misc-non-private-member-variables-in-classes,-modernize-use-trailing-return-type,-misc-no-recursion,-misc-const-correctness,-misc-use-anonymous-namespace,-performance-avoid-endl'
-# note DEV:
-# disabled 'hicpp-signed-bitwise' because it's too noisy
-# (IgnorePositiveIntegerLiterals doesn't seem to work, re-evaluate with Clang 11+)
+Checks: 'clang-diagnostic-*,clang-analyzer-*,modernize*,performance*,readability-*size*,readability*redundant*,-readability-redundant-member-init,-readability-redundant-access-specifiers,misc*,boost-use-to-string,cert*,google-explicit-constructor,-cert-err58-cpp,-modernize-use-nodiscard,-misc-non-private-member-variables-in-classes,-modernize-use-trailing-return-type,-misc-no-recursion,-misc-const-correctness,-misc-use-anonymous-namespace,-readability-redundant-qualified-alias,-performance-enum-size'
WarningsAsErrors: ''
HeaderFilterRegex: ''
@@ -22,4 +19,6 @@ CheckOptions:
value: llvm
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
+ - key: performance-unnecessary-value-param.AllowedTypes
+ value: 'std::(__[A-Za-z0-9_]+::)*exception_ptr$'
...
diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in
index 07ec5e4..d95365b 100644
--- a/docs/Doxyfile.in
+++ b/docs/Doxyfile.in
@@ -30,6 +30,7 @@ EXCLUDE_SYMBOLS = Impl \
# the first sentence of a comment is its summary, there is no need to say so with \brief
JAVADOC_AUTOBRIEF = YES
+ALIASES = "runtimes{2}=\verbatim embed:rst^^:ASIO: ``\1``^^:COROSIO: ``\2``^^\endverbatim"
# Doxygen does not compile anything, so what a compiler would get from config.hpp and from Asio's
# headers is said here -- which is also why the reference takes neither Boost nor a configured
diff --git a/docs/README.md b/docs/README.md
index 96642b7..4e7a799 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -32,7 +32,8 @@ apt-get install doxygen python3-sphinx python3-breathe python3-sphinx-rtd-theme
The target is not part of a regular build, and not there at all where CMake finds no `doxygen` or no
`sphinx-build`, or was told `ANYHTTP_BUILD_DOCS=OFF`. It can be made from a tree of either I/O runtime
-and gives the same result: the comments on the types of the two runtimes are in `asio/runtime.hpp`.
+and gives the same result: Doxygen reads `asio/runtime.hpp` for the runtime layer, whichever runtime
+the tree is on.
## Writing it
@@ -44,6 +45,11 @@ Warnings are errors in both tools, so a public symbol without a comment, a param
* In a comment, Doxygen takes `http::...` and `https://` for a link, and `\c` of either, or of a word
that starts with `[`, comes out empty, which neither tool warns about. So write `errors::...`, as
that is the spelling that holds on both I/O runtimes anyway, and `[...]`.
+* The runtime layer has one section for both I/O runtimes. Its functions come from `asio/runtime.hpp`
+ as everything else does, and so do the codes of `errors::`, each with `\hideinitializer` and a
+ `\runtimes{asio, corosio}` that says what it is on each (an alias in `Doxyfile.in`). Its types,
+ `Task`, `IoTask`, `results`, `error_code` and the others, are declared in `reference.rst` instead,
+ as Breathe would show what they stand for on ASIO only; keep those in step with the headers.
* Code in the guide comes from `snippets.cpp`, between a `// [name]` and a `// [name-end]` comment,
and is shown with `literalinclude`. Only pseudo code is written in place.
* In a page, names link to the reference with `` :cpp:func:`Session::submit` `` and the like, and
diff --git a/docs/io-runtimes.rst b/docs/io-runtimes.rst
index 1414e35..aebb3d9 100644
--- a/docs/io-runtimes.rst
+++ b/docs/io-runtimes.rst
@@ -42,6 +42,12 @@ What the names stand for
* - :cpp:type:`error_code`
- ``boost::system::error_code``
- ``std::error_code``
+ * - :cpp:type:`results\ `
+ - ``std::tuple``
+ - ``capy::results``
+ * - :cpp:type:`IoTask\ `
+ - ``asio::awaitable>``
+ - ``capy::task>``
* - :cpp:type:`TcpEndpoint`, :cpp:type:`UdpEndpoint`
- ``asio::ip::tcp::endpoint``, ``asio::ip::udp::endpoint``
- ``corosio::endpoint``
@@ -79,14 +85,15 @@ example, with the types of the library:
auto async_read_some(asio::mutable_buffer buffer, CompletionToken&& token = CompletionToken());
// ... and the coroutine around it.
- Task> read_some(asio::mutable_buffer buffer);
+ IoTask read_some(asio::mutable_buffer buffer);
// COROSIO: the coroutine.
- Task> read_some(asio::mutable_buffer buffer);
+ IoTask read_some(asio::mutable_buffer buffer);
The coroutine has the same declaration on both, so code that uses only coroutines builds with
-either, which is what the guide does. It yields a tuple with the error first, and reports what goes
-wrong instead of throwing it. Every operation has it: ``read_some``, ``write``, ``write_eof``,
+either, which is what the guide does. It yields :cpp:type:`results`, a tuple with the error first,
+and reports what goes wrong instead of throwing it; :cpp:type:`IoTask\ ` is short
+for ``Task>``. Every operation has it: ``read_some``, ``write``, ``write_eof``,
``submit``, ``get_response``, ``connect``, ``get``, and the others. What it does not have is a
completion token, so an ASIO build that wants one, for a callback, for ``cancel_after`` or to have
errors thrown, uses the ``async_...`` shape, see :ref:`completion-tokens` in the guide.
diff --git a/docs/reference.rst b/docs/reference.rst
index 3117f47..684f156 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -141,22 +141,77 @@ The runtime
#include
-What the interface is written in, and what each name is on ASIO. On COROSIO the same names are
-something else, which :ref:`the table ` has.
+What the interface is written in. The names are the same on both I/O runtimes, and what each
+stands for is the runtime's own, given here for both, as in :ref:`the table `.
-.. doxygentypedef:: anyhttp::Task
+Types
+^^^^^
-.. doxygentypedef:: anyhttp::Executor
+.. cpp:type:: template anyhttp::Task
-.. doxygentypedef:: anyhttp::IpAddress
+ A coroutine, as the runtime runs it.
-.. doxygentypedef:: anyhttp::TcpEndpoint
+ :ASIO: ``asio::awaitable``
+ :COROSIO: ``capy::task``
-.. doxygentypedef:: anyhttp::UdpEndpoint
+.. cpp:type:: template anyhttp::IoTask
-.. doxygentypedef:: anyhttp::error_code
+ An operation, as the coroutine that yields its :cpp:type:`results`: ``IoTask`` is
+ ``Task>``, ``IoTask<>`` one that reports only its error.
-.. doxygentypedef:: anyhttp::system_error
+ :ASIO: ``asio::awaitable>``
+ :COROSIO: ``capy::task>``
+
+.. cpp:type:: template anyhttp::results
+
+ What an operation yields: its error first, then what it has to report besides, which
+ ``auto [ec, n] = co_await reader.read_some(buffer);`` takes apart. Whether that is meaningful
+ when there is an error is up to the operation.
+
+ :ASIO: ``std::tuple``
+ :COROSIO: ``capy::results``, which is ``std::tuple``
+
+.. cpp:type:: anyhttp::error_code
+
+ What every operation reports its outcome with.
+
+ :ASIO: ``boost::system::error_code``
+ :COROSIO: ``std::error_code``
+
+.. cpp:type:: anyhttp::system_error
+
+ What the runtime throws an :cpp:type:`error_code` as.
+
+ :ASIO: ``boost::system::system_error``
+ :COROSIO: ``std::system_error``
+
+.. cpp:type:: anyhttp::Executor
+
+ What sessions, streams and their readers and writers run on.
+
+ :ASIO: ``asio::any_io_executor``
+ :COROSIO: ``capy::any_executor``
+
+.. cpp:type:: anyhttp::IpAddress
+
+ The runtime's own IP address, which the API speaks, too.
+
+ :ASIO: ``asio::ip::address``
+ :COROSIO: ``corosio::ip_address``
+
+.. cpp:type:: anyhttp::TcpEndpoint
+
+ The runtime's own TCP endpoint.
+
+ :ASIO: ``asio::ip::tcp::endpoint``
+ :COROSIO: ``corosio::endpoint``
+
+.. cpp:type:: anyhttp::UdpEndpoint
+
+ The runtime's own UDP endpoint.
+
+ :ASIO: ``asio::ip::udp::endpoint``
+ :COROSIO: ``corosio::endpoint``, the same type as :cpp:type:`TcpEndpoint`
.. doxygentypedef:: anyhttp::DefaultCompletionToken
@@ -165,8 +220,8 @@ something else, which :ref:`the table ` has.
Errors
^^^^^^
-Where the two runtimes spell an error differently, see :ref:`the table `. Anything
-else compares against ``errc::``.
+The codes anyhttp reports where the two runtimes spell them differently. Anything else compares
+against ``errc::``, which is ``boost::system::errc`` on ASIO and ``std::errc`` on COROSIO.
.. doxygenvariable:: anyhttp::errors::eof
diff --git a/docs/snippets.cpp b/docs/snippets.cpp
index 3553f64..91dd1d7 100644
--- a/docs/snippets.cpp
+++ b/docs/snippets.cpp
@@ -109,7 +109,7 @@ Task route(server::Request request, server::Response response)
//
// [read-all]
-Task> read_all(Reader& reader)
+IoTask read_all(Reader& reader)
{
std::string body;
std::array buffer;
@@ -126,8 +126,7 @@ Task> read_all(Reader& reader)
// [read-all-end]
// [post]
-Task> post(Session& session, boost::urls::url url,
- std::string body)
+IoTask post(Session& session, boost::urls::url url, std::string body)
{
auto [submit_ec, request] =
co_await session.submit(url, fields({{"Content-Length", body.size()}}));
@@ -220,8 +219,7 @@ Task round_trip(Session& session, boost::urls::url url, std::string
// [both-ways-end]
// [would-block]
-Task> submit_patiently(Session& session,
- boost::urls::url url)
+IoTask submit_patiently(Session& session, boost::urls::url url)
{
for (;;)
{
@@ -383,8 +381,8 @@ inline void quic_serve(server::Server& server)
}
// [quic-client]
-Task> quic_hello(Executor executor, std::string host,
- std::string port, std::string ca_file)
+IoTask quic_hello(Executor executor, std::string host, std::string port,
+ std::string ca_file)
{
auto [connect_ec, connection] = co_await quic::connect(
executor, std::move(host), std::move(port), {.alpn = "echo", .tls_ca_file = ca_file});
diff --git a/include/anyhttp/asio/net.hpp b/include/anyhttp/asio/net.hpp
index ea6c8fb..161dd42 100644
--- a/include/anyhttp/asio/net.hpp
+++ b/include/anyhttp/asio/net.hpp
@@ -311,12 +311,10 @@ std::pair buffer_sizes(TcpSocket& socket);
void set_buffer_sizes(TcpSocket& socket, int send, int receive);
/// Resolves \p host and \p port (a number): (error_code, endpoints).
-Task>> resolve(Executor executor, std::string host,
- std::string port);
+IoTask> resolve(Executor executor, std::string host, std::string port);
/// Connects \p socket to the first of \p endpoints that takes it: (error_code, endpoint).
-Task> connect(TcpSocket& socket,
- std::vector endpoints);
+IoTask connect(TcpSocket& socket, std::vector endpoints);
inline TlsStream make_tls_stream(TcpSocket&& socket, TlsContext& context)
{
diff --git a/include/anyhttp/asio/runtime.hpp b/include/anyhttp/asio/runtime.hpp
index 9544a16..f6eee1b 100644
--- a/include/anyhttp/asio/runtime.hpp
+++ b/include/anyhttp/asio/runtime.hpp
@@ -71,6 +71,9 @@ namespace anyhttp
{
namespace asio = boost::asio;
+// The reference declares the types from here to errc in docs/reference.rst, with what each is on
+// both runtimes: from here, Breathe would show the ASIO one only.
+
/// A coroutine, as the runtime runs it.
template
using Task = asio::awaitable;
@@ -90,6 +93,22 @@ using UdpEndpoint = asio::ip::udp::endpoint;
/// What every operation reports its outcome with.
using error_code = boost::system::error_code;
+/**
+ * What an operation yields: its error first, then what it has to report besides, which
+ * `auto [ec, n] = co_await reader.read_some(buffer);` takes apart. Whether that is meaningful
+ * when there is an error is up to the operation. Capy's `capy::results` with the runtime's
+ * #error_code, so that on COROSIO the two are the same type.
+ */
+template
+using results = std::tuple;
+
+/**
+ * An operation, as the coroutine that yields its #results: `IoTask` is
+ * `Task>`, `IoTask<>` one that reports only its error.
+ */
+template
+using IoTask = Task>;
+
// =================================================================================================
/**
@@ -107,27 +126,43 @@ namespace errc = boost::system::errc;
namespace errors
{
/// The end of an incoming body.
+/// \runtimes{asio::error::eof,capy::error::eof}
+/// \hideinitializer
inline const error_code eof = asio::error::eof;
/// An incoming body that ended before it was complete: a reset stream, a lost connection.
+/// \runtimes{beast::http::error::partial_message,capy::error::stream_truncated}
+/// \hideinitializer
inline const error_code partial_message = boost::beast::http::error::partial_message;
/// An operation that was cancelled before it completed.
+/// \runtimes{errc::operation_canceled,capy::error::canceled}
+/// \hideinitializer
inline const error_code canceled = make_error_code(errc::operation_canceled);
/// HTTP/1.1: a request or response that has to wait for an earlier one, see Session.
+/// \runtimes{asio::error::would_block,errc::operation_would_block}
+/// \hideinitializer
inline const error_code would_block = asio::error::would_block;
/// A connection that can not carry any more requests or responses.
+/// \runtimes{asio::error::connection_aborted,errc::connection_aborted}
+/// \hideinitializer
inline const error_code connection_aborted = asio::error::connection_aborted;
/// An operation on a Reader or Writer after its implementation has been released.
+/// \runtimes{asio::error::bad_descriptor,errc::bad_file_descriptor}
+/// \hideinitializer
inline const error_code bad_descriptor = asio::error::bad_descriptor;
/// An operation that may be in progress only once at a time.
+/// \runtimes{asio::error::already_started,errc::connection_already_in_progress}
+/// \hideinitializer
inline const error_code already_started = asio::error::already_started;
/// A header section larger than Config::max_header_size.
+/// \runtimes{beast::http::error::header_limit,beast::http::error::header_limit}
+/// \hideinitializer
inline const error_code header_limit = boost::beast::http::error::header_limit;
} // namespace errors
@@ -141,10 +176,7 @@ using system_error = boost::system::system_error;
/// Throws \p ec, for code that reports errors as exceptions, as the runtime's own does.
/// \param ec The error.
-[[noreturn]] inline void throw_error(const error_code& ec)
-{
- throw boost::system::system_error(ec);
-}
+[[noreturn]] inline void throw_error(const error_code& ec) { throw system_error(ec); }
/// \cond internal
/// What `errno` holds, for code that calls the operating system itself.
@@ -280,7 +312,7 @@ inline void launch(const Executor& executor, Task task, F&& on_done)
* other runtime has no tokens, and returns such a task's result directly.
*/
template
-inline void launch(const Executor& executor, Task> task,
+inline void launch(const Executor& executor, IoTask task,
Completion&& handler)
{
auto slot = asio::get_associated_cancellation_slot(handler);
@@ -292,15 +324,14 @@ inline void launch(const Executor& executor, Task>
//
asio::co_spawn(executor, std::move(task),
asio::bind_cancellation_slot(
- slot, asio::bind_executor(
- handler_executor, [handler = std::move(handler)](
- const std::exception_ptr& ep,
- std::tuple result) mutable {
- if (ep)
- std::move(handler)(code(ep), T{}...);
- else
- std::apply(std::move(handler), std::move(result));
- })));
+ slot, asio::bind_executor(handler_executor, [handler = std::move(handler)](
+ const std::exception_ptr& ep,
+ results result) mutable {
+ if (ep)
+ std::move(handler)(code(ep), T{}...);
+ else
+ std::apply(std::move(handler), std::move(result));
+ })));
}
// -------------------------------------------------------------------------------------------------
@@ -437,7 +468,7 @@ class Event
* Waits for the event to be set: auto [ec] = co_await event.wait();. The wait can be
* cancelled, and then completes with \c errors::canceled.
*/
- Task> wait()
+ IoTask<> wait()
{
if (set_)
co_return error_code{};
diff --git a/include/anyhttp/client.hpp b/include/anyhttp/client.hpp
index 927c971..ade69e7 100644
--- a/include/anyhttp/client.hpp
+++ b/include/anyhttp/client.hpp
@@ -216,7 +216,7 @@ class Request : public Writer
/// \c async_get_response() as a coroutine:
/// auto [ec, response] = co_await request.get_response();
/// \return The error and the response.
- Task> get_response();
+ IoTask get_response();
private:
#if ANYHTTP_ASIO
@@ -285,7 +285,7 @@ class Client
/// \c async_connect() as a coroutine: auto [ec, session] = co_await client.connect();
/// \return The error and the session.
- Task> connect();
+ IoTask connect();
private:
#if ANYHTTP_ASIO
diff --git a/include/anyhttp/client_impl.hpp b/include/anyhttp/client_impl.hpp
index beceed3..dbcbc71 100644
--- a/include/anyhttp/client_impl.hpp
+++ b/include/anyhttp/client_impl.hpp
@@ -27,7 +27,7 @@ class Request::Impl : public Writer::Impl
virtual void async_get_response(GetResponseHandler&& handler) = 0;
/// async_get_response() as a coroutine, see Reader::Impl::read_some().
- virtual Task> get_response()
+ virtual IoTask get_response()
{
co_return co_await initiate(
[this](GetResponseHandler handler) { async_get_response(std::move(handler)); });
diff --git a/include/anyhttp/common.hpp b/include/anyhttp/common.hpp
index 1eae82f..fad40a5 100644
--- a/include/anyhttp/common.hpp
+++ b/include/anyhttp/common.hpp
@@ -1,6 +1,5 @@
#pragma once
-#include
#include
#include
@@ -16,7 +15,6 @@
#include
#include
#include
-#include
#include
// =================================================================================================
@@ -81,7 +79,7 @@ class FieldValue
/// \param value The value of the header field.
template
requires std::formattable
- FieldValue(const T& value)
+ FieldValue(const T& value) // NOLINT(google-explicit-constructor)
{
if constexpr (std::convertible_to)
view = value;
@@ -103,7 +101,10 @@ class FieldValue
/// \endcond
/// \return The value, which lives as long as the FieldValue and what it refers to.
- operator std::string_view() const noexcept { return view; }
+ operator std::string_view() const noexcept // NOLINT(google-explicit-constructor)
+ {
+ return view;
+ }
private:
std::string_view view;
@@ -248,7 +249,10 @@ std::string what(const anyhttp::error_code& ec);
struct HttpDate
{
std::array chars;
- operator std::string_view() const noexcept { return {chars.data(), chars.size()}; }
+ operator std::string_view() const noexcept // NOLINT(google-explicit-constructor)
+ {
+ return {chars.data(), chars.size()};
+ }
};
/// Formats \p tp as an HTTP date, clamped to the years 0000 to 9999 the format has room for.
diff --git a/include/anyhttp/corosio/net.hpp b/include/anyhttp/corosio/net.hpp
index 7185081..5bb994d 100644
--- a/include/anyhttp/corosio/net.hpp
+++ b/include/anyhttp/corosio/net.hpp
@@ -263,11 +263,9 @@ std::pair buffer_sizes(TcpSocket& socket);
void set_buffer_sizes(TcpSocket& socket, int send, int receive);
-Task>> resolve(Executor executor, std::string host,
- std::string port);
+IoTask> resolve(Executor executor, std::string host, std::string port);
-Task> connect(TcpSocket& socket,
- std::vector endpoints);
+IoTask connect(TcpSocket& socket, std::vector endpoints);
inline TlsStream make_tls_stream(TcpSocket&& socket, TlsContext& context)
{
@@ -320,7 +318,7 @@ class Signal
void notify() { waker_.wake(); }
- Task> wait()
+ IoTask<> wait()
{
auto [ec] = co_await waker_.wait();
co_return std::tuple{ec};
diff --git a/include/anyhttp/corosio/runtime.hpp b/include/anyhttp/corosio/runtime.hpp
index d9aef9f..d43e6ca 100644
--- a/include/anyhttp/corosio/runtime.hpp
+++ b/include/anyhttp/corosio/runtime.hpp
@@ -96,6 +96,11 @@ using UdpEndpoint = corosio::endpoint;
using std::error_code;
+using capy::results;
+
+template
+using IoTask = Task>;
+
// =================================================================================================
/// Portable error conditions, see asio/runtime.hpp.
@@ -140,7 +145,7 @@ struct CompletionState
{
capy::continuation continuation;
const capy::await_context* env = nullptr;
- std::optional> result;
+ std::optional> result;
std::optional>> on_stop;
bool starting = false; // the operation is being started, see Initiation::await_suspend()
@@ -162,7 +167,7 @@ template
struct CompletionTraits
{
using State = CompletionState;
- using Result = std::tuple;
+ using Result = results;
};
} // namespace detail
@@ -186,7 +191,7 @@ class Completion
using State = detail::CompletionState;
Completion() noexcept = default;
- Completion(std::nullptr_t) noexcept {}
+ Completion(std::nullptr_t) noexcept {} // NOLINT(*-explicit-constructor)
explicit Completion(State* state) noexcept : state_(state) {}
Completion(Completion&& other) noexcept : state_(std::exchange(other.state_, nullptr)) {}
Completion& operator=(Completion&& other) noexcept
@@ -302,22 +307,22 @@ class Initiation
return std::noop_coroutine();
}
- typename Traits::Result await_resume() { return std::move(*state_.result); }
+ Traits::Result await_resume() { return std::move(*state_.result); }
private:
template
- void canceled(std::type_identity>)
+ void canceled(std::type_identity>)
{
state_.result.emplace(errors::canceled, Args{}...);
}
Init init_;
- typename Traits::State state_;
+ Traits::State state_;
};
} // namespace detail
-/// Starts an operation that completes a Completion, and waits for it.
+/// Starts an operation that completes a \c Completion, and waits for it.
template
auto initiate(Init&& init)
{
@@ -336,8 +341,13 @@ inline void launch(const Executor& executor, Task task, F&& on_done)
{
auto done = std::make_shared>(std::forward(on_done));
capy::run_async(
- executor, [done]() noexcept { (*done)(std::exception_ptr{}); },
- [done](std::exception_ptr ep) noexcept { (*done)(ep); })(std::move(task));
+ executor,
+ [done]() noexcept { //
+ (*done)(std::exception_ptr{});
+ },
+ [done](std::exception_ptr ep) noexcept { //
+ (*done)(ep);
+ })(std::move(task));
}
/**
@@ -345,7 +355,7 @@ inline void launch(const Executor& executor, Task task, F&& on_done)
* so cancelling the caller cancels the task.
*/
template
-inline void launch(const Executor& executor, Task> task,
+inline void launch(const Executor& executor, IoTask task,
Completion&& handler)
{
std::stop_token token;
@@ -355,11 +365,12 @@ inline void launch(const Executor& executor, Task>
auto shared = std::make_shared>(std::move(handler));
capy::run_async(
executor, token,
- [shared](std::tuple result) noexcept {
+ [shared](results result) noexcept { //
std::apply(std::move(*shared), std::move(result));
},
- [shared](std::exception_ptr ep) noexcept { std::move (*shared)(code(ep), T{}...); })(
- std::move(task));
+ [shared](std::exception_ptr ep) noexcept { //
+ std::move (*shared)(code(ep), T{}...);
+ })(std::move(task));
}
// -------------------------------------------------------------------------------------------------
@@ -463,7 +474,7 @@ using value_t = std::conditional_t, std::monostate, T>;
* keeping its value. What it throws passes through.
*/
template
-capy::task> as_io(Task task, std::optional>& result)
+capy::task> as_io(Task task, std::optional>& result)
{
if constexpr (std::is_void_v)
{
@@ -472,7 +483,7 @@ capy::task> as_io(Task task, std::optional>& resul
}
else
result.emplace(co_await std::move(task));
- co_return capy::results<>{};
+ co_return results<>{};
}
} // namespace detail
@@ -537,8 +548,6 @@ class Event
void set() { event_.set(); }
void clear() noexcept { event_.clear(); }
bool is_set() const noexcept { return event_.is_set(); }
-
- /// auto [ec] = co_await event.wait();
auto wait() { return event_.wait(); }
private:
@@ -615,7 +624,7 @@ auto write(Stream& stream, const ConstBufferSequence& buffers)
/// Peeks at what has arrived on \p socket, without taking it. corosio has no flags for its
/// receive operations, so this waits for readiness and peeks at the native socket.
template
-Task> peek(Socket& socket, asio::mutable_buffer buffer)
+IoTask peek(Socket& socket, asio::mutable_buffer buffer)
{
for (;;)
{
@@ -636,7 +645,7 @@ Task> peek(Socket& socket, asio::mutable_buffer b
/// read_some(): corosio's datagram operations do not copy their buffer sequence, as its stream
/// operations do, but point to it, so it has to outlive the operation.
template
-Task> receive(Socket& socket, asio::mutable_buffer buffer)
+IoTask receive(Socket& socket, asio::mutable_buffer buffer)
{
const capy::mutable_buffer buffers(buffer.data(), buffer.size());
auto [ec, n] = co_await socket.recv(buffers);
diff --git a/include/anyhttp/detail/detect.hpp b/include/anyhttp/detail/detect.hpp
index 1fb6a37..308ca87 100644
--- a/include/anyhttp/detail/detect.hpp
+++ b/include/anyhttp/detail/detect.hpp
@@ -61,7 +61,7 @@ enum class Detected
* \p buffer: the session that takes over the connection starts with what is in there.
*/
template
-Task> detect(Socket& socket, DynamicBuffer& buffer)
+IoTask detect(Socket& socket, DynamicBuffer& buffer)
{
std::array first;
auto [ec, n] = co_await io::peek(socket, asio::buffer(first));
diff --git a/include/anyhttp/h1/io.hpp b/include/anyhttp/h1/io.hpp
index e185fa4..5c53fa5 100644
--- a/include/anyhttp/h1/io.hpp
+++ b/include/anyhttp/h1/io.hpp
@@ -62,8 +62,8 @@ inline error_code to_error_code(const boost::system::error_code& ec)
* lost.
*/
template
-Task> read_some(Stream& stream, DynamicBuffer& buffer,
- http::basic_parser& parser)
+IoTask read_some(Stream& stream, DynamicBuffer& buffer,
+ http::basic_parser& parser)
{
size_t parsed = 0;
boost::system::error_code ec;
@@ -110,8 +110,8 @@ Task> read_some(Stream& stream, DynamicBuffer& bu
/// Reads until the parser has the whole header, as Beast's \c http::async_read_header().
template
-Task> read_header(Stream& stream, DynamicBuffer& buffer,
- http::basic_parser& parser)
+IoTask read_header(Stream& stream, DynamicBuffer& buffer,
+ http::basic_parser& parser)
{
size_t parsed = 0;
while (!parser.is_header_done())
@@ -127,8 +127,7 @@ Task> read_header(Stream& stream, DynamicBuffer&
/// Reads until the parser has the whole message, as Beast's \c http::async_read() with a parser.
template
-Task> read(Stream& stream, DynamicBuffer& buffer,
- http::basic_parser& parser)
+IoTask read(Stream& stream, DynamicBuffer& buffer, http::basic_parser& parser)
{
size_t parsed = 0;
while (!parser.is_done())
@@ -144,9 +143,8 @@ Task> read(Stream& stream, DynamicBuffer& buffer,
/// Reads a whole message into \p message, as Beast's \c http::async_read() with a message.
template
-Task>
-read_message(Stream& stream, DynamicBuffer& buffer,
- http::message>& message)
+IoTask read_message(Stream& stream, DynamicBuffer& buffer,
+ http::message>& message)
{
http::parser parser;
parser.eager(true);
@@ -166,8 +164,7 @@ read_message(Stream& stream, DynamicBuffer& buffer,
* but \c http::error::need_buffer, which is passed on here.
*/
template
-Task>
-write_some(Stream& stream, http::serializer& serializer)
+IoTask write_some(Stream& stream, http::serializer& serializer)
{
if (serializer.is_done())
co_return std::tuple{error_code{}, size_t{0}};
@@ -197,8 +194,7 @@ write_some(Stream& stream, http::serializer& serializer
* here, this also stops when a \c buffer_body has been written that is not the last.
*/
template
-Task> write_until(Stream& stream, Serializer& serializer,
- Predicate done)
+IoTask write_until(Stream& stream, Serializer& serializer, Predicate done)
{
size_t written = 0;
while (!done(serializer))
@@ -216,7 +212,7 @@ Task> write_until(Stream& stream, Serializer& ser
/// Writes the header, as Beast's \c http::async_write_header().
template
-Task> write_header(Stream& stream, Serializer& serializer)
+IoTask write_header(Stream& stream, Serializer& serializer)
{
serializer.split(true);
return h1::write_until(stream, serializer, [](auto& sr) { return sr.is_header_done(); });
@@ -224,15 +220,14 @@ Task> write_header(Stream& stream, Serializer& se
/// Writes all there is, as Beast's \c http::async_write() with a serializer.
template
-Task> write(Stream& stream, Serializer& serializer)
+IoTask write(Stream& stream, Serializer& serializer)
{
return h1::write_until(stream, serializer, [](auto& sr) { return sr.is_done(); });
}
/// Writes all of \p message, as Beast's \c http::async_write() with a message.
template
-Task> write_message(Stream& stream,
- http::message& message)
+IoTask write_message(Stream& stream, http::message& message)
{
http::serializer serializer{message};
co_return co_await h1::write(stream, serializer);
diff --git a/include/anyhttp/h1/session.hpp b/include/anyhttp/h1/session.hpp
index 45cb61e..18c4a37 100644
--- a/include/anyhttp/h1/session.hpp
+++ b/include/anyhttp/h1/session.hpp
@@ -247,10 +247,10 @@ class ClientSession : public ClientSessionBase, public BeastSession
void async_submit(SubmitHandler&& handler, std::string_view method, boost::urls::url url,
const Fields& headers) override;
- Task> submit(std::string method, boost::urls::url url,
- Fields headers) override;
+ IoTask submit(std::string method, boost::urls::url url,
+ Fields headers) override;
Task do_session(Buffer&& data) override;
- Task> shutdown() override;
+ IoTask<> shutdown() override;
// ----------------------------------------------------------------------------------------------
diff --git a/include/anyhttp/h2/session.hpp b/include/anyhttp/h2/session.hpp
index e01af9c..3ebde16 100644
--- a/include/anyhttp/h2/session.hpp
+++ b/include/anyhttp/h2/session.hpp
@@ -253,7 +253,7 @@ class ClientSession : public ClientReference, public NGHttp2SessionImpl
ClientSession(client::Client::Impl& parent, Executor executor, Stream&& stream);
Task do_session(Buffer&& data) override;
- Task> shutdown() override;
+ IoTask<> shutdown() override;
void on_alt_svc(std::string_view field_value) override { client().on_alt_svc(field_value); }
};
diff --git a/include/anyhttp/h2/session_details.hpp b/include/anyhttp/h2/session_details.hpp
index 7b11eb2..61b87ae 100644
--- a/include/anyhttp/h2/session_details.hpp
+++ b/include/anyhttp/h2/session_details.hpp
@@ -440,7 +440,7 @@ Task ClientSession::do_session(Buffer&& buffer)
// -------------------------------------------------------------------------------------------------
template
-Task> ClientSession::shutdown()
+IoTask<> ClientSession::shutdown()
{
if (std::exchange(this->shutdown_started_, true) || this->session_done_.is_set())
co_return std::tuple{error_code{}};
diff --git a/include/anyhttp/h2v2/session.hpp b/include/anyhttp/h2v2/session.hpp
index df1c7de..d413044 100644
--- a/include/anyhttp/h2v2/session.hpp
+++ b/include/anyhttp/h2v2/session.hpp
@@ -274,7 +274,7 @@ class ClientSession : public ClientReference, public NGHttp2SessionImpl
ClientSession(client::Client::Impl& parent, Executor executor, Stream&& stream);
Task do_session(Buffer&& data) override;
- Task> shutdown() override;
+ IoTask<> shutdown() override;
void on_alt_svc(std::string_view field_value) override { client().on_alt_svc(field_value); }
};
diff --git a/include/anyhttp/h2v2/session_details.hpp b/include/anyhttp/h2v2/session_details.hpp
index d7dd119..43a7a29 100644
--- a/include/anyhttp/h2v2/session_details.hpp
+++ b/include/anyhttp/h2v2/session_details.hpp
@@ -369,7 +369,7 @@ Task ClientSession::do_session(Buffer&& buffer)
// -------------------------------------------------------------------------------------------------
template
-Task> ClientSession::shutdown()
+IoTask<> ClientSession::shutdown()
{
if (std::exchange(this->shutdown_started_, true) || this->session_done_.is_set())
co_return std::tuple{error_code{}};
diff --git a/include/anyhttp/quic.hpp b/include/anyhttp/quic.hpp
index c0f9ddc..cab70d7 100644
--- a/include/anyhttp/quic.hpp
+++ b/include/anyhttp/quic.hpp
@@ -19,7 +19,6 @@
// same UDP port as HTTP/3.
//
-#include "common.hpp"
#include "reader.hpp"
#include "writer.hpp"
@@ -34,7 +33,6 @@
#include
#include
#include
-#include
namespace anyhttp::quic
{
@@ -211,7 +209,7 @@ class Connection
*
* \return The error and the stream.
*/
- std::tuple open_stream();
+ results open_stream();
#if ANYHTTP_ASIO
/// Waits for the next stream the peer opens. Fails with \c errors::connection_aborted once the
@@ -233,7 +231,7 @@ class Connection
/// \c async_accept_stream() as a coroutine: auto [ec, stream] = co_await
/// connection.accept_stream();
/// \return The error and the stream.
- Task> accept_stream();
+ IoTask accept_stream();
/// Closes the connection: CONNECTION_CLOSE with the application error \p code. What is still
/// open fails with \c errc::connection_reset.
@@ -266,8 +264,7 @@ using ConnectHandler = Completion;
/// \param port The port of the server.
/// \param config The protocol, and how to speak it.
/// \return The error and the connection.
-Task> connect(Executor executor, std::string host,
- std::string port, Config config);
+IoTask connect(Executor executor, std::string host, std::string port, Config config);
#if ANYHTTP_ASIO
/// \cond internal
diff --git a/include/anyhttp/quic/streams.hpp b/include/anyhttp/quic/streams.hpp
index aa3095e..4f6abed 100644
--- a/include/anyhttp/quic/streams.hpp
+++ b/include/anyhttp/quic/streams.hpp
@@ -90,7 +90,7 @@ class StreamApplication final : public QuicApplication
//
// What Connection offers.
//
- std::tuple open_stream();
+ results open_stream();
void async_accept_stream(AcceptStreamHandler&& handler);
/// Puts `stream` at the end of the write queue, unless it is in there already.
diff --git a/include/anyhttp/reader.hpp b/include/anyhttp/reader.hpp
index 21bd17b..d4a95d7 100644
--- a/include/anyhttp/reader.hpp
+++ b/include/anyhttp/reader.hpp
@@ -134,7 +134,7 @@ class Reader
/// Reads a part of the incoming body: auto [ec, n] = co_await reader.read_some(buffer);
/// \param buffer Where to put what has been read.
/// \return The error, and how many bytes have been read.
- Task> read_some(asio::mutable_buffer buffer);
+ IoTask read_some(asio::mutable_buffer buffer);
/// \overload
///
@@ -145,7 +145,7 @@ class Reader
template
requires(asio::is_mutable_buffer_sequence::value &&
!std::convertible_to)
- Task> read_some(const Buffers& buffers)
+ IoTask read_some(const Buffers& buffers)
{
for (auto& buffer : buffers)
if (buffer.size() > 0)
@@ -158,7 +158,7 @@ class Reader
///
/// For capy's buffer sequences, which is what makes a Reader a \c capy::ReadStream.
template
- Task> read_some(Buffers buffers)
+ IoTask read_some(Buffers buffers)
{
for (auto it = capy::buffer_sequence_begin(buffers); it != capy::buffer_sequence_end(buffers);
++it)
diff --git a/include/anyhttp/reader_impl.hpp b/include/anyhttp/reader_impl.hpp
index 58ed602..55a456d 100644
--- a/include/anyhttp/reader_impl.hpp
+++ b/include/anyhttp/reader_impl.hpp
@@ -49,7 +49,7 @@ class Reader::Impl : public std::enable_shared_from_this
// handler (HTTP/2, HTTP/3) makes the coroutine cheap, through initiate(). Doing the I/O in a
// coroutine (HTTP/1.1) makes the handler shape cost a spawn, through launch().
//
- virtual Task> read_some(asio::mutable_buffer buffer)
+ virtual IoTask read_some(asio::mutable_buffer buffer)
{
co_return co_await initiate([this, buffer](ReadSomeHandler handler) { //
async_read_some(buffer, std::move(handler));
diff --git a/include/anyhttp/runtime.hpp b/include/anyhttp/runtime.hpp
index cce563b..b7d9c03 100644
--- a/include/anyhttp/runtime.hpp
+++ b/include/anyhttp/runtime.hpp
@@ -9,7 +9,8 @@
// public API front-ends and the test fixtures test ANYHTTP_ASIO or ANYHTTP_COROSIO: the protocol
// backends are written once, against these names.
//
-// Task, Executor, error_code, Completion, system_error
+// Task, IoTask, results, Executor, error_code, Completion,
+// system_error
// IpAddress, TcpEndpoint, UdpEndpoint -- the runtime's own
// errc (portable error conditions), errors:: (the codes of the API contract), throw_error()
// last_error() -- errno, as an error_code
diff --git a/include/anyhttp/server.hpp b/include/anyhttp/server.hpp
index cfaeeca..3077ef0 100644
--- a/include/anyhttp/server.hpp
+++ b/include/anyhttp/server.hpp
@@ -268,7 +268,7 @@ class Response : public Writer
/// \param status_code The status code of the response.
/// \param headers The header fields of the response.
/// \return The error.
- Task> submit(unsigned int status_code, Fields headers);
+ IoTask<> submit(unsigned int status_code, Fields headers);
private:
#if ANYHTTP_ASIO
diff --git a/include/anyhttp/server_impl.hpp b/include/anyhttp/server_impl.hpp
index be30dff..387d0f7 100644
--- a/include/anyhttp/server_impl.hpp
+++ b/include/anyhttp/server_impl.hpp
@@ -46,10 +46,11 @@ class Response::Impl : public Writer::Impl
const Fields& fields) = 0;
/// async_submit() as a coroutine, see Reader::Impl::read_some().
- virtual Task> submit(unsigned int status_code, Fields fields)
+ virtual IoTask<> submit(unsigned int status_code, Fields fields)
{
- co_return co_await initiate(
- [&](StatusHandler handler) { async_submit(std::move(handler), status_code, fields); });
+ co_return co_await initiate([&](StatusHandler handler) { //
+ async_submit(std::move(handler), status_code, fields);
+ });
}
};
diff --git a/include/anyhttp/session.hpp b/include/anyhttp/session.hpp
index 24010d7..3ba7456 100644
--- a/include/anyhttp/session.hpp
+++ b/include/anyhttp/session.hpp
@@ -238,8 +238,7 @@ class Session
/// \param target The URL of the request.
/// \param headers The header fields of the request.
/// \return The error and the request.
- Task> submit(boost::urls::url target,
- Fields headers = {});
+ IoTask