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

Code before:
    ///
    /// #[tokio::main]
    /// async fn main() -> io::Result<()> {
    ///     let socket = UdpSocket::bind("0.0.0.0:8080")?;
    ///     socket.set_nonblocking(true)?;
    ///     let async_fd = AsyncFd::new(socket)?;
    ///
    ///     let written = loop {
    ///         let mut guard = async_fd.writable().await?;
    ///         match guard.try_io(|inner| inner.get_ref().send(&[1, 2])) {
    ///             Ok(result) => {
    ///                 break result?;
    ///             }
    ///             Err(_would_block) => {
    ///                 continue;
    ///             }
    ///         }
    ///     };
    ///
    ///     println!("wrote {written} bytes");
    ///
    ///     Ok(())
    /// }
    /// ```
    ///
    /// Using this method, this logic can instead be written as:
    ///
    /// ```no_run
    /// use tokio::io::{Interest, unix::AsyncFd};
    ///
    /// use std::io;
    /// use std::net::UdpSocket;
    ///
    /// #[tokio::main]
    /// async fn main() -> io::Result<()> {
    ///     let socket = UdpSocket::bind("0.0.0.0:8080")?;
    ///     socket.set_nonblocking(true)?;
    ///     let async_fd = AsyncFd::new(socket)?;
    ///
    ///     let written = async_fd
    ///         .async_io(Interest::WRITABLE, |inner| inner.send(&[1, 2]))
    ///         .await?;
    ///
    ///     println!("wrote {written} bytes");
    ///
    ///     Ok(())
    /// }
    /// ```
    ///
    /// The readiness of the file descriptor is awaited and when the file descriptor is ready,
    /// the provided closure is called. The closure should attempt to perform

Review comment (suggestion):
Instead of including both examples here, I would refer to an example on `try_io` (add it if missing). Otherwise, if someone only looks at the examples without looking at the text, they may get confused.

Code after:
    /// # struct Dox<T> { inner: T }
    /// # impl<T> Dox<T> {
    /// #     async fn writable(&self) -> Result<&Self> {
    /// #         Ok(self)
    /// #     }
    /// #     fn try_io<R>(&self, _: impl FnMut(&T) -> Result<R>) -> Result<Result<R>> {
    /// #         panic!()
    /// #     }
    /// async fn async_io<R>(&self, mut f: impl FnMut(&T) -> io::Result<R>) -> io::Result<R> {
    ///     loop {
    ///         // or `readable` if called with the read interest.
    ///         let guard = self.writable().await?;
    ///
    ///         match guard.try_io(&mut f) {
    ///             Ok(result) => return result,
    ///             Err(_would_block) => continue,
    ///         }
    ///     }
    /// }
    /// # }
    /// ```
    ///
    /// The closure should only return a [`WouldBlock`] error if it has performed
    /// an IO operation on the file descriptor that failed due to the file descriptor not being
    /// ready. Returning a [`WouldBlock`] error in any other situation will
    /// incorrectly clear the readiness flag, which can cause the file descriptor to
    /// behave incorrectly.
    ///
    /// The closure should not perform the IO operation using any of the methods
    /// defined on the Tokio [`AsyncFd`] type, as this will mess with the
    /// readiness flag and can cause the file descriptor to behave incorrectly.
    ///
    /// This method is not intended to be used with combined interests.
    /// The closure should perform only one type of IO operation, so it should not
    /// require more than one ready state. This method may panic or sleep forever
    /// if it is called with a combined interest.
    ///
    /// # Examples
    ///
    /// This example sends some bytes on the inner [`std::net::UdpSocket`]. The `async_io`
    /// method waits for readiness, and retries if the send operation does block. This example
    /// is equivalent to the one given for [`try_io`].
    ///
    /// ```no_run
    /// use tokio::io::{Interest, unix::AsyncFd};
    ///
    /// use std::io;
    /// use std::net::UdpSocket;
    ///
    /// #[tokio::main]
    /// async fn main() -> io::Result<()> {