Repository: tokio-rs/tokio
File: tokio-util/src/io/sink_writer.rs (Rust)

Code before:
use futures_sink::Sink;

use pin_project_lite::pin_project;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::AsyncWrite;

pin_project! {
    /// Convert a [`Sink`] of byte chunks into an [`AsyncWrite`].
    ///
    /// Bytes are sent into the sink and the sink is flushed once all bytes are sent.
    /// If an error occurs during the sending progress, the number of sent but
    /// unflushed bytes are saved in case the flushing operation stays unsuccessful.
    /// For the inverse operation of defining an [`AsyncWrite`] from a [`Sink`] you
    /// need to define a [`codec`].
    ///
    /// # Example
    ///
    /// ```
    /// use bytes::Bytes;
    /// use futures_util::SinkExt;
    /// use std::io::{Error, ErrorKind};
    /// use tokio::io::AsyncWriteExt;
    /// use tokio_util::io::{SinkWriter, CopyToBytes};
    /// use tokio_util::sync::PollSender;
    ///
    /// # #[tokio::main]
    /// # async fn main() -> Result<(), Error> {
    ///  // Construct a channel pair to send data across and wrap a pollable sink.
    ///  // Note that the sink must mimic a writable object, e.g. have `std::io::Error`
    ///  // as its error type.
    ///  let (tx, mut rx) = tokio::sync::mpsc::channel::<Bytes>(1);
    ///  let mut writer = SinkWriter::new(CopyToBytes::new(
    ///    PollSender::new(tx).sink_map_err(|_| Error::from(ErrorKind::BrokenPipe)),
    ///  ));
    ///  // Write data to our interface...
    ///  let data: [u8; 4] = [1, 2, 3, 4];
    ///  let _ = writer.write(&data).await?;
    ///  // ... and receive it.
    ///  assert_eq!(data.to_vec(), rx.recv().await.unwrap().to_vec());

Review comment (suggestion):
I'm struggling to understand this paragraph. Does my rewrite mean the same thing, or have I misunderstood you completely?

```suggestion
    /// Each write to the `SinkWriter` is converted into a send of `&[u8]` to the `Sink`. Flushes and shutdown are propagated to the sink's flush and close methods.
    ///
    /// This adapter implements `AsyncWrite` for `Sink<&[u8]>`. If you want to implement `Sink<_>` for `AsyncWrite`, see [`codec`]; if you need to implement `AsyncWrite` for `Sink<Bytes>`, see [`CopyToBytes`].
```

Note that you'll need to update the references set to use this as-is, so please read the documentation after building it to make sure it flows nicely.

Code after:
use futures_sink::Sink;

use pin_project_lite::pin_project;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::AsyncWrite;

pin_project! {
    /// Convert a [`Sink`] of byte chunks into an [`AsyncWrite`].
    ///
    /// Whenever you write to this [`SinkWriter`], the supplied bytes are
    /// forwarded to the inner [`Sink`]. When `shutdown` is called on this
    /// [`SinkWriter`], the inner sink is closed.
    ///
    /// This adapter takes a `Sink<&[u8]>` and provides an [`AsyncWrite`] impl
    /// for it. Because of the lifetime, this trait is relatively rarely
    /// implemented. The main ways to get a `Sink<&[u8]>` that you can use with
    /// this type are:
    ///
    ///  * With the codec module by implementing the [`Encoder`]`<&[u8]>` trait.
    ///  * By wrapping a `Sink<Bytes>` in a [`CopyToBytes`].
    ///  * Manually implementing `Sink<&[u8]>` directly.
    ///
    /// The opposite conversion of implementing `Sink<_>` for an [`AsyncWrite`]
    /// is done using the [`codec`] module.
    ///
    /// # Example
    ///
    /// ```
    /// use bytes::Bytes;
    /// use futures_util::SinkExt;
    /// use std::io::{Error, ErrorKind};
    /// use tokio::io::AsyncWriteExt;
    /// use tokio_util::io::{SinkWriter, CopyToBytes};
    /// use tokio_util::sync::PollSender;
    ///
    /// # #[tokio::main(flavor = "current_thread")]
    /// # async fn main() -> Result<(), Error> {
    /// // We use an mpsc channel as an example of a `Sink<Bytes>`.
    /// let (tx, mut rx) = tokio::sync::mpsc::channel::<Bytes>(1);