Partially based on tungstenite commits
- 46dfd9ed3ee75b0261e9f5f71c8e70492407248b by Alexey Galakhov
- 31010fd636b3edc683199e3182ea34d799118d5b by Alexey Galakhov
Instead simply send an owned Closed message. This simplifies the code
and among other things also handles errors like WouldBlock correctly
instead of handling them like a real error.
The same functionality is already provided via StreamExt::send() and
unlike the custom implementation it handles WouldBlock correctly and not
as an error.
As a side effect also gets rid of unsafe code and raw pointers.
We have the problem that external read operations (i.e. the Stream impl)
can trigger both read (AsyncRead) and write (AsyncWrite) operations on
the underyling stream. At the same time write operations (i.e. the Sink
impl) can trigger write operations (AsyncWrite) too.
Both the Stream and the Sink can be used on two different tasks, but it
is required that AsyncRead and AsyncWrite are only ever used by a single
task (or better: with a single waker) at a time.
Doing otherwise would cause only the latest waker to be remembered, so
in our case either the Stream or the Sink impl would potentially wait
forever to be woken up because only the other one would've been woken
up.
To solve this we implement a waker proxy that has two slots (one for
read, one for write) to store wakers. One waker proxy is always passed
to the AsyncRead, the other to AsyncWrite so that they will only ever
have to store a single waker, but internally we dispatch any wakeups to
up to two actual wakers (one from the Sink impl and one from the Stream
impl).