libunifex
libunifex copied to clipboard
Question about any_sender_of usage
First of all, libunifex is amazing ! Thanks for your great work.
I'm trying to implement networking stuff using libunifex, all the basic things are ok (send, recv, connect, accept, ...), but, I'm running into troubles when I try to implement ssl socket.
In this context I need to bind either a send_sender
or a recv_sender
to a any_sender_of<size_t>
(for the handshake procedure).
I minimized the area of the problem I'm encountering into your io_uring_test.cpp, in the main
function I added:
auto read_or_write = [&](bool read = true) -> any_sender_of<> {
if (read) {
return read_file(scheduler, "test.txt");
} else {
return write_new_file(scheduler, "test.txt");
}
};
sync_wait(read_or_write());
Then I have the following error using clang-11:
In file included from <...>/libunifex/examples/linux/io_uring_test.cpp:24:
<...>/libunifex/include/unifex/let.hpp:76:5: error: no matching function for call to object of type 'const struct _set_error_fn'
unifex::set_error(std::move(op_.receiver_), (Error &&) error);
see: example branch.
I am missing something ?
Is this actually the purpose of an any_sender_of<...>
?
Is the error handling part is just missing from any_sender_of<...>
?
Thanks !
The problem is that the io_uring_context can propagate errors of two types: std::exception_ptr
and std::error_code
. any_sender_of<>
is only able to handle std::exception_ptr
. There currently isn't a generalization of any_sender_of<>
than can handle more than std::exception_ptr
.
A good solution, and something we should probably have anyway, is a variant sender. Since it knows a priori what types it may contain, it doesn't have to guess what the error type is.
A stop-gap would be to change any_sender_of
to handle error types other than std::exception_ptr
by passing them to std::make_exception_ptr
. That's not a super-awesome solution, though.
Thanks for the reply !
I quick-fixed io_uring_ring
context usability with coroutines and any_sender_of<>
with those 2 commits:
- https://github.com/Garcia6l20/libunifex/commit/f87af151bbb8b520eea9e1a4abacf1da0135c7fe
- https://github.com/Garcia6l20/libunifex/commit/8b6abf69d09c0453f5842128a1d234fe19db197f
Are you interested for those changes, or are you planning to address them in another way ? (ie.: variant_sender
)
Not those changes exactly, since that would lead to unnecessary code bloat for the vast majority of senders, which don't send std::error_code
through the error channel. The io_uring_context
is maintained by @lewissbaker. I wonder how he thinks we should deal with this.
So, the simple path would be to make io_uring_context
send std::system_error
(wrapped into std::exception_ptr
) rather than std::error_code
. Isn't it ?
That would be one simple fix. Another is to put that logic into the type erased receiver itself so that any errors that are not already exception_ptrs get wrapped.
Yes, I think this could be part of the type-erasing wrapper, but that would forward the non-exception_ptr
error into another customisation point, like get_exception_ptr(err)
, that allowed you to customise how std::error_code
was converted to an exception_ptr
. i.e. so that it could be wrapped in a std::system_error
instead.
For now, it could be hard-coded as logic in the type-erasing wrappers.
e.g. the receiver it passes down could have two overloads of set_error()
. One taking exception_ptr
and the other taking an error_code
that forwards on to set_error(*this, std::make_exception_ptr(std::system_error(ec)))
Longer term, it probably makes sense to allow the any_sender_of type to be parameterisable with both a list of set_value overloads and a list of set_error overloads that it expects/supports, rather than have them hard-coded to exception_ptr or some other error-types.