Skip to content

Commit

Permalink
doc: Update Boost links and avoid using agrpc::bind_allocator in exam…
Browse files Browse the repository at this point in the history
…ples
  • Loading branch information
Tradias committed Dec 16, 2023
1 parent 4eab032 commit bf1691e
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 34 deletions.
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@

[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=Tradias_asio-grpc&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=Tradias_asio-grpc) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=Tradias_asio-grpc&metric=coverage)](https://sonarcloud.io/dashboard?id=Tradias_asio-grpc) [![vcpkg](https://repology.org/badge/version-for-repo/vcpkg/asio-grpc.svg?header=vcpkg)](https://repology.org/project/asio-grpc/versions) [![conan](https://repology.org/badge/version-for-repo/conancenter/asio-grpc.svg?header=conan)](https://repology.org/project/asio-grpc/versions) [![hunter](https://img.shields.io/badge/hunter-asio_grpc-green.svg)](https://hunter.readthedocs.io/en/latest/packages/pkg/asio-grpc.html)

An [Executor, Networking TS](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/Executor1.html#boost_asio.reference.Executor1.standard_executors) and [std::execution](http://wg21.link/p2300) interface to [grpc::CompletionQueue](https://grpc.github.io/grpc/cpp/classgrpc_1_1_completion_queue.html) for writing asynchronous [gRPC](https://grpc.io/) clients and servers using C++20 coroutines, Boost.Coroutines, Asio's stackless coroutines, callbacks, sender/receiver and more.
An [Executor, Networking TS](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/Executor1.html#boost_asio.reference.Executor1.standard_executors) and [std::execution](http://wg21.link/p2300) interface to [grpc::CompletionQueue](https://grpc.github.io/grpc/cpp/classgrpc_1_1_completion_queue.html) for writing asynchronous [gRPC](https://grpc.io/) clients and servers using C++20 coroutines, Boost.Coroutines, Asio's stackless coroutines, callbacks, sender/receiver and more.

# Features

> In v3 the new [ClientRPC](https://tradias.github.io/asio-grpc/md_doc_client_rpc_cheat_sheet.html) and [ServerRPC](https://tradias.github.io/asio-grpc/md_doc_server_rpc_cheat_sheet.html) APIs will replace the current free-function API. Your feedback is highly appreciated. Please communicate via issues.
* Asio [ExecutionContext](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/ExecutionContext.html) compatible wrapper around [grpc::CompletionQueue](https://grpc.github.io/grpc/cpp/classgrpc_1_1_completion_queue.html)
* Support for all RPC types: unary, client-streaming, server-streaming and bidirectional-streaming with any mix of Asio [CompletionToken](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers) as well as [Sender](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#sender-concept), including allocator customization
* Support for asynchronously waiting for [grpc::Alarm](https://grpc.github.io/grpc/cpp/classgrpc_1_1_alarm.html)s including cancellation through [cancellation_slot](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/cancellation_slot.html)s and [StopToken](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#stoptoken-concept)s
* Support for `std::execution` through [libunifex](https://github.com/facebookexperimental/libunifex)
* Support for generic gRPC clients and servers (aka. proxies)
* Asio [ExecutionContext](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/ExecutionContext.html) compatible wrapper around [grpc::CompletionQueue](https://grpc.github.io/grpc/cpp/classgrpc_1_1_completion_queue.html)
* Support for all RPC types: unary, client-streaming, server-streaming and bidirectional-streaming with any mix of Asio [CompletionToken](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers) as well as [Sender](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#sender-concept), including allocator customization
* Support for asynchronously waiting for [grpc::Alarms](https://grpc.github.io/grpc/cpp/classgrpc_1_1_alarm.html) including cancellation through [cancellation_slots](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/cancellation_slot.html) and [StopTokens](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#stoptoken-concept)
* Support for `std::execution` through either [libunifex](https://github.com/facebookexperimental/libunifex) or [stdexec](https://github.com/NVIDIA/stdexec)
* Support for generic gRPC clients and servers
* No extra codegen required, works with the vanilla gRPC C++ plugin (`grpc_cpp_plugin`)
* No-Boost version with [standalone Asio](https://github.com/chriskohlhoff/asio)
* No-Asio version with [libunifex](https://github.com/facebookexperimental/libunifex) or [stdexec](https://github.com/NVIDIA/stdexec)
* CMake function to generate gRPC source files: [asio_grpc_protobuf_generate](/cmake/AsioGrpcProtobufGenerator.cmake)
* CMake function to easily generate gRPC source files: [asio_grpc_protobuf_generate](/cmake/AsioGrpcProtobufGenerator.cmake)

# Requirements

Asio-grpc is a C++17, header-only library. To install it, CMake (3.14+) is all that is needed.

To use it, [gRPC](https://grpc.io/) and either [Boost.Asio](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio.html) (min. 1.74.0), [standalone Asio](https://github.com/chriskohlhoff/asio) (min. 1.17.0), [libunifex](https://github.com/facebookexperimental/libunifex) or [stdexec](https://github.com/NVIDIA/stdexec) must be present and linked into your application.
To use it, [gRPC](https://grpc.io/) and either [Boost.Asio](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio.html) (min. 1.74.0), [standalone Asio](https://github.com/chriskohlhoff/asio) (min. 1.17.0), [libunifex](https://github.com/facebookexperimental/libunifex) or [stdexec](https://github.com/NVIDIA/stdexec) must be present and linked into your application.

Supported compilers are GCC 8+, Clang 10+, AppleClang 14+ and latest MSVC.
Officially supported compilers are GCC 8+, Clang 10+, AppleClang 14+ and latest MSVC.

# Usage

Expand All @@ -39,7 +39,7 @@ The library can be added to a CMake project using either `add_subdirectory` or `

Clone the repository into a subdirectory of your CMake project. Then add it and link it to your target.

Using [Boost.Asio](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio.html):
Using [Boost.Asio](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio.html):

```cmake
add_subdirectory(/path/to/asio-grpc)
Expand Down Expand Up @@ -90,7 +90,7 @@ cmake --build build --target install

Locate it and link it to your target.

Using [Boost.Asio](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio.html):
Using [Boost.Asio](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio.html):

```cmake
# Make sure CMAKE_PREFIX_PATH contains /desired/installation/directory
Expand Down Expand Up @@ -259,13 +259,13 @@ Request scenario: string_100B

The main workhorses of this library are the [agrpc::GrpcContext](https://tradias.github.io/asio-grpc/classagrpc_1_1_grpc_context.html) and its `executor_type` - [agrpc::GrpcExecutor](https://tradias.github.io/asio-grpc/classagrpc_1_1_basic_grpc_executor.html).

The [agrpc::GrpcContext](https://tradias.github.io/asio-grpc/classagrpc_1_1_grpc_context.html) implements [asio::execution_context](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/execution_context.html) and can be used as an argument to Asio functions that expect an `ExecutionContext` like [asio::spawn](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/spawn/overload2.html).
The [agrpc::GrpcContext](https://tradias.github.io/asio-grpc/classagrpc_1_1_grpc_context.html) implements [asio::execution_context](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/execution_context.html) and can be used as an argument to Asio functions that expect an `ExecutionContext` like [asio::spawn](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/spawn/overload2.html).

Likewise, the [agrpc::GrpcExecutor](https://tradias.github.io/asio-grpc/classagrpc_1_1_basic_grpc_executor.html) satisfies the [Executor and Networking TS](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/Executor1.html#boost_asio.reference.Executor1.standard_executors) and [Scheduler](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#scheduler) requirements and can therefore be used in places where Asio/libunifex expects an `Executor` or `Scheduler`.
Likewise, the [agrpc::GrpcExecutor](https://tradias.github.io/asio-grpc/classagrpc_1_1_basic_grpc_executor.html) satisfies the [Executor and Networking TS](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/Executor1.html#boost_asio.reference.Executor1.standard_executors) and [Scheduler](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#scheduler) requirements and can therefore be used in places where Asio/libunifex expects an `Executor` or `Scheduler`.

The API for RPCs is modeled after the asynchronous, tag-based API of gRPC. As an example, the equivalent for `grpc::ClientAsyncReader<helloworld::HelloReply>.Read(helloworld::HelloReply*, void*)` would be `agrpc::ClientRPC.read(helloworld::HelloReply&, CompletionToken)`.

Instead of the `void*` tag in the gRPC API the functions in this library expect a [CompletionToken](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers). Asio comes with several CompletionTokens already: [C++20 coroutine](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/use_awaitable.html), [stackless coroutine](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/coroutine.html), [callback](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/executor_binder.html) and [Boost.Coroutine](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/basic_yield_context.html). There is also a special token called `agrpc::use_sender` that causes RPC functions to return a [Sender](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#sender-concept).
Instead of the `void*` tag in the gRPC API the functions in this library expect a [CompletionToken](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers). Asio comes with several CompletionTokens already: [C++20 coroutine](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/use_awaitable.html), [stackless coroutine](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/coroutine.html), callback and [Boost.Coroutine](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/basic_yield_context.html). There is also a special token called `agrpc::use_sender` that causes RPC functions to return a [Sender](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#sender-concept).

If you are interested in learning more about the implementation details of this library then check out [this blog article](https://medium.com/3yourmind/c-20-coroutines-for-asynchronous-grpc-services-5b3dab1d1d61).

Expand Down
8 changes: 4 additions & 4 deletions doc/completion_token.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# Completion token

The last argument to all async functions in this library is a [CompletionToken](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers). It can be used to customize how to receive notification of the completion of the asynchronous operation. Some examples:
The last argument to all async functions in this library is a [CompletionToken](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers). It can be used to customize how to receive notification of the completion of the asynchronous operation. Some examples:

## Callback

@snippet server.cpp alarm-with-callback

## use_sender

`agrpc::use_sender` causes free functions in this library to return a [sender](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#typedsender-concept). They can e.g. be combined with `unifex::task` to asynchronously process RPCs using `co_await`:
`agrpc::use_sender` causes free functions in this library to return a [Sender](https://github.com/facebookexperimental/libunifex/blob/main/doc/concepts.md#typedsender-concept). They can e.g. be combined with `unifex::task` to asynchronously process RPCs using `co_await`:

@snippet unifex_client.cpp unifex-server-streaming-client-side

## Custom allocator

Asio-grpc attempts to get the completion handler's associated allocator by calling [asio::get_associated_allocator](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/get_associated_allocator.html) and uses to allocate intermediate storage, typically for the completion handler itself. Prior to invocation of the completion handler all storage is deallocated.
Asio-grpc attempts to get the completion handler's associated allocator by calling [asio::get_associated_allocator](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/get_associated_allocator.html) and uses to allocate intermediate storage, typically for the completion handler itself. Prior to invocation of the completion handler all storage is deallocated.

The associated allocator can be customized using `agrpc::bind_allocator` (or `asio::bind_allocator` since Boost.Asio 1.79):
The associated allocator can be customized using `asio::bind_allocator` (since Boost.Asio 1.79):

@snippet server.cpp alarm-with-allocator-aware-awaitable
6 changes: 3 additions & 3 deletions doc/using_asio_io_context.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Using Asio io_context

@note Due to limitations of the gRPC CompletionQueue and Callback API an [asio::io_context](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/io_context.html) cannot be used to handle RPCs directly. See the end of this document for a detailed explanation.
@note Due to limitations of the gRPC CompletionQueue and Callback API an [asio::io_context](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/io_context.html) cannot be used to handle RPCs directly. See the end of this document for a detailed explanation.

This article describes how to interoperate between a GrpcContext and an [asio::io_context](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/io_context.html).
This article describes how to interoperate between a GrpcContext and an [asio::io_context](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/io_context.html).

## Implicitly constructed io_context

Since a GrpcContext is also an [asio::execution_context](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/execution_context.html) it supports Asio's [Service](https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/reference/Service.html) mechanism. The following code will therefore implicitly create an io_context, a background thread, run the io_context on that thread and post the completion of `async_wait` onto the GrpcContext where the lambda is being invoked.
Since a GrpcContext is also an [asio::execution_context](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/execution_context.html) it supports Asio's [Service](https://www.boost.org/doc/libs/1_84_0/doc/html/boost_asio/reference/Service.html) mechanism. The following code will therefore implicitly create an io_context, a background thread, run the io_context on that thread and post the completion of `async_wait` onto the GrpcContext where the lambda is being invoked.

@snippet{code} io_context.cpp implicit_io_context

Expand Down
2 changes: 1 addition & 1 deletion example/file-transfer-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ asio::awaitable<bool, agrpc::GrpcExecutor> handle_send_file_request(asio::io_con
const std::string& file_path)
{
// These buffers are used to customize allocation of completion handlers.
example::Buffer<300> buffer1;
example::Buffer<308> buffer1;
example::Buffer<40> buffer2;

example::v1::SendFileRequest first_buffer;
Expand Down
4 changes: 2 additions & 2 deletions example/helper/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

#include "one_shot_allocator.hpp"

#include <agrpc/bind_allocator.hpp>
#include <boost/asio/bind_allocator.hpp>

#include <cstddef>
#include <type_traits>
Expand All @@ -34,7 +34,7 @@ struct Buffer
template <class Target>
[[nodiscard]] auto bind_allocator(Target&& target) noexcept
{
return agrpc::bind_allocator(allocator(), std::forward<Target>(target));
return boost::asio::bind_allocator(allocator(), std::forward<Target>(target));
}

alignas(std::max_align_t) std::byte data_[Capacity];
Expand Down
6 changes: 3 additions & 3 deletions example/snippets/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ asio::awaitable<void> agrpc_alarm_rvalue(agrpc::GrpcContext& grpc_context)
asio::awaitable<void> timer_with_different_completion_tokens(agrpc::GrpcContext& grpc_context)
{
std::allocator<void> my_allocator{};
grpc::Alarm alarm;
agrpc::Alarm alarm{grpc_context};
const auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(1);
/* [alarm-with-callback] */
agrpc::wait(alarm, deadline, asio::bind_executor(grpc_context, [&](bool /*wait_ok*/) {}));
alarm.wait(deadline, [&](bool /*wait_ok*/) {});
/* [alarm-with-callback] */

/* [alarm-with-allocator-aware-awaitable] */
co_await agrpc::wait(alarm, deadline, agrpc::bind_allocator(my_allocator, asio::use_awaitable));
co_await alarm.wait(deadline, asio::bind_allocator(my_allocator, asio::use_awaitable));
/* [alarm-with-allocator-aware-awaitable] */
}

Expand Down
2 changes: 1 addition & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ add_subdirectory(proto)

add_subdirectory(utils)

add_subdirectory(src)
# add_subdirectory(src)

if(ASIO_GRPC_BOOST_ASIO_HAS_CO_AWAIT AND ASIO_GRPC_ENABLE_CPP20_TESTS_AND_EXAMPLES)
add_subdirectory(example)
Expand Down
10 changes: 4 additions & 6 deletions test/cmake/superbuild/src/out_var.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,10 @@ void run_out_var()
out_var::msg::Request request;
request.set_integer(42);

grpc::ServerAsyncResponseWriter<out_var::msg::Response> writer{&server_context};
auto cb = boost::asio::bind_executor(grpc_context, [](bool) {});
const auto is_void =
std::is_same_v<void, decltype(agrpc::request(out_var_v1_rpc, service, server_context, request, writer, cb))>;

out_var::msg::Request response;
using RPC = agrpc::ServerRPC<&out_var::v1::Test::AsyncService::RequestUnary>;
RPC::Response response;
auto cb = [](bool) {};
const auto is_void = std::is_same_v<void, decltype(std::declval<RPC>().finish(response, {}, cb))>;

grpc_context.run();
}

0 comments on commit bf1691e

Please sign in to comment.