From ff028bb540f85c3399796ae1e692df6cc0c2cf44 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 26 Sep 2019 14:21:27 -0400 Subject: [PATCH] Improve compile times and add comments --- src/io/buf_read/mod.rs | 314 ++++++++++++++++++++------------------ src/io/read/mod.rs | 322 +++++++++++++++++++++------------------ src/io/seek.rs | 92 +++++------ src/io/write/mod.rs | 255 +++++++++++++++++-------------- src/os/unix/net/mod.rs | 6 +- src/stream/stream/mod.rs | 90 +++++++---- src/utils.rs | 63 ++++++-- 7 files changed, 632 insertions(+), 510 deletions(-) diff --git a/src/io/buf_read/mod.rs b/src/io/buf_read/mod.rs index ad8df85..d34b2ae 100644 --- a/src/io/buf_read/mod.rs +++ b/src/io/buf_read/mod.rs @@ -22,91 +22,99 @@ cfg_if! { } extension_trait! { - /// Allows reading from a buffered byte stream. - /// - /// This trait is a re-export of [`futures::io::AsyncBufRead`] and is an async version of - /// [`std::io::BufRead`]. - /// - /// The [provided methods] do not really exist in the trait itself, but they become - /// available when the prelude is imported: - /// - /// ``` - /// # #[allow(unused_imports)] - /// use async_std::prelude::*; - /// ``` - /// - /// [`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html - /// [`futures::io::AsyncBufRead`]: - /// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html - /// [provided methods]: #provided-methods + #[doc = r#" + Allows reading from a buffered byte stream. + + This trait is a re-export of [`futures::io::AsyncBufRead`] and is an async version of + [`std::io::BufRead`]. + + The [provided methods] do not really exist in the trait itself, but they become + available when the prelude is imported: + + ``` + # #[allow(unused_imports)] + use async_std::prelude::*; + ``` + + [`std::io::BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html + [`futures::io::AsyncBufRead`]: + https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html + [provided methods]: #provided-methods + "#] pub trait BufRead [BufReadExt: futures_io::AsyncBufRead] { - /// Returns the contents of the internal buffer, filling it with more data from the - /// inner reader if it is empty. - /// - /// This function is a lower-level call. It needs to be paired with the [`consume`] - /// method to function properly. When calling this method, none of the contents will be - /// "read" in the sense that later calling `read` may return the same contents. As - /// such, [`consume`] must be called with the number of bytes that are consumed from - /// this buffer to ensure that the bytes are never returned twice. - /// - /// [`consume`]: #tymethod.consume - /// - /// An empty buffer returned indicates that the stream has reached EOF. + #[doc = r#" + Returns the contents of the internal buffer, filling it with more data from the + inner reader if it is empty. + + This function is a lower-level call. It needs to be paired with the [`consume`] + method to function properly. When calling this method, none of the contents will be + "read" in the sense that later calling `read` may return the same contents. As + such, [`consume`] must be called with the number of bytes that are consumed from + this buffer to ensure that the bytes are never returned twice. + + [`consume`]: #tymethod.consume + + An empty buffer returned indicates that the stream has reached EOF. + "#] // TODO: write a proper doctest with `consume` fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - /// Tells this buffer that `amt` bytes have been consumed from the buffer, so they - /// should no longer be returned in calls to `read`. + #[doc = r#" + Tells this buffer that `amt` bytes have been consumed from the buffer, so they + should no longer be returned in calls to `read`. + "#] fn consume(self: Pin<&mut Self>, amt: usize); - /// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. - /// - /// This function will read bytes from the underlying stream until the delimiter or EOF - /// is found. Once found, all bytes up to, and including, the delimiter (if found) will - /// be appended to `buf`. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::io::BufReader; - /// use async_std::prelude::*; - /// - /// let mut file = BufReader::new(File::open("a.txt").await?); - /// - /// let mut buf = Vec::with_capacity(1024); - /// let n = file.read_until(b'\n', &mut buf).await?; - /// # - /// # Ok(()) }) } - /// ``` - /// - /// Multiple successful calls to `read_until` append all bytes up to and including to - /// `buf`: - /// ``` - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::io::BufReader; - /// use async_std::prelude::*; - /// - /// let from: &[u8] = b"append\nexample\n"; - /// let mut reader = BufReader::new(from); - /// let mut buf = vec![]; - /// - /// let mut size = reader.read_until(b'\n', &mut buf).await?; - /// assert_eq!(size, 7); - /// assert_eq!(buf, b"append\n"); - /// - /// size += reader.read_until(b'\n', &mut buf).await?; - /// assert_eq!(size, from.len()); - /// - /// assert_eq!(buf, from); - /// # - /// # Ok(()) }) } - /// ``` + #[doc = r#" + Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. + + This function will read bytes from the underlying stream until the delimiter or EOF + is found. Once found, all bytes up to, and including, the delimiter (if found) will + be appended to `buf`. + + If successful, this function will return the total number of bytes read. + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::io::BufReader; + use async_std::prelude::*; + + let mut file = BufReader::new(File::open("a.txt").await?); + + let mut buf = Vec::with_capacity(1024); + let n = file.read_until(b'\n', &mut buf).await?; + # + # Ok(()) }) } + ``` + + Multiple successful calls to `read_until` append all bytes up to and including to + `buf`: + ``` + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::io::BufReader; + use async_std::prelude::*; + + let from: &[u8] = b"append\nexample\n"; + let mut reader = BufReader::new(from); + let mut buf = vec![]; + + let mut size = reader.read_until(b'\n', &mut buf).await?; + assert_eq!(size, 7); + assert_eq!(buf, b"append\n"); + + size += reader.read_until(b'\n', &mut buf).await?; + assert_eq!(size, from.len()); + + assert_eq!(buf, from); + # + # Ok(()) }) } + ``` + "#] fn read_until<'a>( &'a mut self, byte: u8, @@ -123,42 +131,44 @@ extension_trait! { } } - /// Reads all bytes and appends them into `buf` until a newline (the 0xA byte) is - /// reached. - /// - /// This function will read bytes from the underlying stream until the newline - /// delimiter (the 0xA byte) or EOF is found. Once found, all bytes up to, and - /// including, the delimiter (if found) will be appended to `buf`. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// If this function returns `Ok(0)`, the stream has reached EOF. - /// - /// # Errors - /// - /// This function has the same error semantics as [`read_until`] and will also return - /// an error if the read bytes are not valid UTF-8. If an I/O error is encountered then - /// `buf` may contain some bytes already read in the event that all data read so far - /// was valid UTF-8. - /// - /// [`read_until`]: #method.read_until - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::io::BufReader; - /// use async_std::prelude::*; - /// - /// let mut file = BufReader::new(File::open("a.txt").await?); - /// - /// let mut buf = String::new(); - /// file.read_line(&mut buf).await?; - /// # - /// # Ok(()) }) } - /// ``` + #[doc = r#" + Reads all bytes and appends them into `buf` until a newline (the 0xA byte) is + reached. + + This function will read bytes from the underlying stream until the newline + delimiter (the 0xA byte) or EOF is found. Once found, all bytes up to, and + including, the delimiter (if found) will be appended to `buf`. + + If successful, this function will return the total number of bytes read. + + If this function returns `Ok(0)`, the stream has reached EOF. + + # Errors + + This function has the same error semantics as [`read_until`] and will also return + an error if the read bytes are not valid UTF-8. If an I/O error is encountered then + `buf` may contain some bytes already read in the event that all data read so far + was valid UTF-8. + + [`read_until`]: #method.read_until + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::io::BufReader; + use async_std::prelude::*; + + let mut file = BufReader::new(File::open("a.txt").await?); + + let mut buf = String::new(); + file.read_line(&mut buf).await?; + # + # Ok(()) }) } + ``` + "#] fn read_line<'a>( &'a mut self, buf: &'a mut String, @@ -174,35 +184,37 @@ extension_trait! { } } - /// Returns a stream over the lines of this byte stream. - /// - /// The stream returned from this function will yield instances of - /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline byte - /// (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. - /// - /// [`io::Result`]: type.Result.html - /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::io::BufReader; - /// use async_std::prelude::*; - /// - /// let file = File::open("a.txt").await?; - /// let mut lines = BufReader::new(file).lines(); - /// let mut count = 0; - /// - /// while let Some(line) = lines.next().await { - /// line?; - /// count += 1; - /// } - /// # - /// # Ok(()) }) } - /// ``` + #[doc = r#" + Returns a stream over the lines of this byte stream. + + The stream returned from this function will yield instances of + [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline byte + (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. + + [`io::Result`]: type.Result.html + [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::io::BufReader; + use async_std::prelude::*; + + let file = File::open("a.txt").await?; + let mut lines = BufReader::new(file).lines(); + let mut count = 0; + + while let Some(line) = lines.next().await { + line?; + count += 1; + } + # + # Ok(()) }) } + ``` + "#] fn lines(self) -> Lines where Self: Unpin + Sized, @@ -221,11 +233,11 @@ extension_trait! { self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn consume(self: Pin<&mut Self>, amt: usize) { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -234,11 +246,11 @@ extension_trait! { self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn consume(self: Pin<&mut Self>, amt: usize) { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -251,11 +263,11 @@ extension_trait! { self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn consume(self: Pin<&mut Self>, amt: usize) { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -268,7 +280,7 @@ extension_trait! { } fn consume(self: Pin<&mut Self>, amt: usize) { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } } diff --git a/src/io/read/mod.rs b/src/io/read/mod.rs index 3acfc28..3827681 100644 --- a/src/io/read/mod.rs +++ b/src/io/read/mod.rs @@ -27,87 +27,100 @@ cfg_if! { } extension_trait! { - /// Allows reading from a byte stream. - /// - /// This trait is a re-export of [`futures::io::AsyncRead`] and is an async version of - /// [`std::io::Read`]. - /// - /// Methods other than [`poll_read`] and [`poll_read_vectored`] do not really exist in the - /// trait itself, but they become available when the prelude is imported: - /// - /// ``` - /// # #[allow(unused_imports)] - /// use async_std::prelude::*; - /// ``` - /// - /// [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html - /// [`futures::io::AsyncRead`]: - /// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html - /// [`poll_read`]: #tymethod.poll_read - /// [`poll_read_vectored`]: #method.poll_read_vectored + #[doc = r#" + Allows reading from a byte stream. + + This trait is a re-export of [`futures::io::AsyncRead`] and is an async version of + [`std::io::Read`]. + + Methods other than [`poll_read`] and [`poll_read_vectored`] do not really exist in the + trait itself, but they become available when the prelude is imported: + + ``` + # #[allow(unused_imports)] + use async_std::prelude::*; + ``` + + [`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html + [`futures::io::AsyncRead`]: + https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncRead.html + [`poll_read`]: #tymethod.poll_read + [`poll_read_vectored`]: #method.poll_read_vectored + "#] pub trait Read [ReadExt: futures_io::AsyncRead] { - /// Attempt to read from the `AsyncRead` into `buf`. + #[doc = r#" + Attempt to read from the `AsyncRead` into `buf`. + "#] fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll>; - /// Attempt to read from the `AsyncRead` into `bufs` using vectored IO operations. + #[doc = r#" + Attempt to read from the `AsyncRead` into `bufs` using vectored IO operations. + "#] fn poll_read_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } - /// Reads some bytes from the byte stream. - /// - /// Returns the number of bytes read from the start of the buffer. - /// - /// If the return value is `Ok(n)`, then it must be guaranteed that - /// `0 <= n <= buf.len()`. A nonzero `n` value indicates that the buffer has been - /// filled in with `n` bytes of data. If `n` is `0`, then it can indicate one of two - /// scenarios: - /// - /// 1. This reader has reached its "end of file" and will likely no longer be able to - /// produce bytes. Note that this does not mean that the reader will always no - /// longer be able to produce bytes. - /// 2. The buffer specified was 0 bytes in length. - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::prelude::*; - /// - /// let mut file = File::open("a.txt").await?; - /// - /// let mut buf = vec![0; 1024]; - /// let n = file.read(&mut buf).await?; - /// # - /// # Ok(()) }) } - /// ``` - fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> impl Future> + 'a [ReadFuture<'a, Self>] + #[doc = r#" + Reads some bytes from the byte stream. + + Returns the number of bytes read from the start of the buffer. + + If the return value is `Ok(n)`, then it must be guaranteed that + `0 <= n <= buf.len()`. A nonzero `n` value indicates that the buffer has been + filled in with `n` bytes of data. If `n` is `0`, then it can indicate one of two + scenarios: + + 1. This reader has reached its "end of file" and will likely no longer be able to + produce bytes. Note that this does not mean that the reader will always no + longer be able to produce bytes. + 2. The buffer specified was 0 bytes in length. + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::prelude::*; + + let mut file = File::open("a.txt").await?; + + let mut buf = vec![0; 1024]; + let n = file.read(&mut buf).await?; + # + # Ok(()) }) } + ``` + "#] + fn read<'a>( + &'a mut self, + buf: &'a mut [u8], + ) -> impl Future> + 'a [ReadFuture<'a, Self>] where Self: Unpin { ReadFuture { reader: self, buf } } - /// Like [`read`], except that it reads into a slice of buffers. - /// - /// Data is copied to fill each buffer in order, with the final buffer written to - /// possibly being only partially filled. This method must behave as a single call to - /// [`read`] with the buffers concatenated would. - /// - /// The default implementation calls [`read`] with either the first nonempty buffer - /// provided, or an empty one if none exists. - /// - /// [`read`]: #tymethod.read + #[doc = r#" + Like [`read`], except that it reads into a slice of buffers. + + Data is copied to fill each buffer in order, with the final buffer written to + possibly being only partially filled. This method must behave as a single call to + [`read`] with the buffers concatenated would. + + The default implementation calls [`read`] with either the first nonempty buffer + provided, or an empty one if none exists. + + [`read`]: #tymethod.read + "#] fn read_vectored<'a>( &'a mut self, bufs: &'a mut [IoSliceMut<'a>], @@ -118,31 +131,33 @@ extension_trait! { ReadVectoredFuture { reader: self, bufs } } - /// Reads all bytes from the byte stream. - /// - /// All bytes read from this stream will be appended to the specified buffer `buf`. - /// This function will continuously call [`read`] to append more data to `buf` until - /// [`read`] returns either `Ok(0)` or an error. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// [`read`]: #tymethod.read - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::prelude::*; - /// - /// let mut file = File::open("a.txt").await?; - /// - /// let mut buf = Vec::new(); - /// file.read_to_end(&mut buf).await?; - /// # - /// # Ok(()) }) } - /// ``` + #[doc = r#" + Reads all bytes from the byte stream. + + All bytes read from this stream will be appended to the specified buffer `buf`. + This function will continuously call [`read`] to append more data to `buf` until + [`read`] returns either `Ok(0)` or an error. + + If successful, this function will return the total number of bytes read. + + [`read`]: #tymethod.read + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::prelude::*; + + let mut file = File::open("a.txt").await?; + + let mut buf = Vec::new(); + file.read_to_end(&mut buf).await?; + # + # Ok(()) }) } + ``` + "#] fn read_to_end<'a>( &'a mut self, buf: &'a mut Vec, @@ -158,28 +173,30 @@ extension_trait! { } } - /// Reads all bytes from the byte stream and appends them into a string. - /// - /// If successful, this function will return the number of bytes read. - /// - /// If the data in this stream is not valid UTF-8 then an error will be returned and - /// `buf` will be left unmodified. - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::prelude::*; - /// - /// let mut file = File::open("a.txt").await?; - /// - /// let mut buf = String::new(); - /// file.read_to_string(&mut buf).await?; - /// # - /// # Ok(()) }) } - /// ``` + #[doc = r#" + Reads all bytes from the byte stream and appends them into a string. + + If successful, this function will return the number of bytes read. + + If the data in this stream is not valid UTF-8 then an error will be returned and + `buf` will be left unmodified. + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::prelude::*; + + let mut file = File::open("a.txt").await?; + + let mut buf = String::new(); + file.read_to_string(&mut buf).await?; + # + # Ok(()) }) } + ``` + "#] fn read_to_string<'a>( &'a mut self, buf: &'a mut String, @@ -196,44 +213,49 @@ extension_trait! { } } - /// Reads the exact number of bytes required to fill `buf`. - /// - /// This function reads as many bytes as necessary to completely fill the specified - /// buffer `buf`. - /// - /// No guarantees are provided about the contents of `buf` when this function is - /// called, implementations cannot rely on any property of the contents of `buf` being - /// true. It is recommended that implementations only write data to `buf` instead of - /// reading its contents. - /// - /// If this function encounters an "end of file" before completely filling the buffer, - /// it returns an error of the kind [`ErrorKind::UnexpectedEof`]. The contents of - /// `buf` are unspecified in this case. - /// - /// If any other read error is encountered then this function immediately returns. The - /// contents of `buf` are unspecified in this case. - /// - /// If this function returns an error, it is unspecified how many bytes it has read, - /// but it will never read more than would be necessary to completely fill the buffer. - /// - /// [`ErrorKind::UnexpectedEof`]: enum.ErrorKind.html#variant.UnexpectedEof - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::prelude::*; - /// - /// let mut file = File::open("a.txt").await?; - /// - /// let mut buf = vec![0; 10]; - /// file.read_exact(&mut buf).await?; - /// # - /// # Ok(()) }) } - /// ``` - fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> impl Future> + 'a [ReadExactFuture<'a, Self>] + #[doc = r#" + Reads the exact number of bytes required to fill `buf`. + + This function reads as many bytes as necessary to completely fill the specified + buffer `buf`. + + No guarantees are provided about the contents of `buf` when this function is + called, implementations cannot rely on any property of the contents of `buf` being + true. It is recommended that implementations only write data to `buf` instead of + reading its contents. + + If this function encounters an "end of file" before completely filling the buffer, + it returns an error of the kind [`ErrorKind::UnexpectedEof`]. The contents of + `buf` are unspecified in this case. + + If any other read error is encountered then this function immediately returns. The + contents of `buf` are unspecified in this case. + + If this function returns an error, it is unspecified how many bytes it has read, + but it will never read more than would be necessary to completely fill the buffer. + + [`ErrorKind::UnexpectedEof`]: enum.ErrorKind.html#variant.UnexpectedEof + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::prelude::*; + + let mut file = File::open("a.txt").await?; + + let mut buf = vec![0; 10]; + file.read_exact(&mut buf).await?; + # + # Ok(()) }) } + ``` + "#] + fn read_exact<'a>( + &'a mut self, + buf: &'a mut [u8], + ) -> impl Future> + 'a [ReadExactFuture<'a, Self>] where Self: Unpin, { @@ -247,7 +269,7 @@ extension_trait! { cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -257,7 +279,7 @@ extension_trait! { cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -271,7 +293,7 @@ extension_trait! { cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -281,7 +303,7 @@ extension_trait! { cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } } diff --git a/src/io/seek.rs b/src/io/seek.rs index a9234f9..274eee7 100644 --- a/src/io/seek.rs +++ b/src/io/seek.rs @@ -14,53 +14,59 @@ cfg_if! { } extension_trait! { - /// Allows seeking through a byte stream. - /// - /// This trait is a re-export of [`futures::io::AsyncSeek`] and is an async version of - /// [`std::io::Seek`]. - /// - /// The [provided methods] do not really exist in the trait itself, but they become - /// available when the prelude is imported: - /// - /// ``` - /// # #[allow(unused_imports)] - /// use async_std::prelude::*; - /// ``` - /// - /// [`std::io::Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html - /// [`futures::io::AsyncSeek`]: - /// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html - /// [provided methods]: #provided-methods + #[doc = r#" + Allows seeking through a byte stream. + + This trait is a re-export of [`futures::io::AsyncSeek`] and is an async version of + [`std::io::Seek`]. + + The [provided methods] do not really exist in the trait itself, but they become + available when the prelude is imported: + + ``` + # #[allow(unused_imports)] + use async_std::prelude::*; + ``` + + [`std::io::Seek`]: https://doc.rust-lang.org/std/io/trait.Seek.html + [`futures::io::AsyncSeek`]: + https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncSeek.html + [provided methods]: #provided-methods + "#] pub trait Seek [SeekExt: futures_io::AsyncSeek] { - /// Attempt to seek to an offset, in bytes, in a stream. + #[doc = r#" + Attempt to seek to an offset, in bytes, in a stream. + "#] fn poll_seek( self: Pin<&mut Self>, cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll>; - /// Seeks to a new position in a byte stream. - /// - /// Returns the new position in the byte stream. - /// - /// A seek beyond the end of stream is allowed, but behavior is defined by the - /// implementation. - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::io::SeekFrom; - /// use async_std::prelude::*; - /// - /// let mut file = File::open("a.txt").await?; - /// - /// let file_len = file.seek(SeekFrom::End(0)).await?; - /// # - /// # Ok(()) }) } - /// ``` + #[doc = r#" + Seeks to a new position in a byte stream. + + Returns the new position in the byte stream. + + A seek beyond the end of stream is allowed, but behavior is defined by the + implementation. + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::io::SeekFrom; + use async_std::prelude::*; + + let mut file = File::open("a.txt").await?; + + let file_len = file.seek(SeekFrom::End(0)).await?; + # + # Ok(()) }) } + ``` + "#] fn seek( &mut self, pos: SeekFrom, @@ -78,7 +84,7 @@ extension_trait! { cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -88,7 +94,7 @@ extension_trait! { cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -102,7 +108,7 @@ extension_trait! { cx: &mut Context<'_>, pos: SeekFrom, ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } } diff --git a/src/io/write/mod.rs b/src/io/write/mod.rs index 27e7920..5e1ecc8 100644 --- a/src/io/write/mod.rs +++ b/src/io/write/mod.rs @@ -24,99 +24,115 @@ cfg_if! { } extension_trait! { - /// Allows writing to a byte stream. - /// - /// This trait is a re-export of [`futures::io::AsyncWrite`] and is an async version of - /// [`std::io::Write`]. - /// - /// Methods other than [`poll_write`], [`poll_write_vectored`], [`poll_flush`], and - /// [`poll_close`] do not really exist in the trait itself, but they become available when - /// the prelude is imported: - /// - /// ``` - /// # #[allow(unused_imports)] - /// use async_std::prelude::*; - /// ``` - /// - /// [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html - /// [`futures::io::AsyncWrite`]: - /// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html - /// [`poll_write`]: #tymethod.poll_write - /// [`poll_write_vectored`]: #method.poll_write_vectored - /// [`poll_flush`]: #tymethod.poll_flush - /// [`poll_close`]: #tymethod.poll_close + #[doc = r#" + Allows writing to a byte stream. + + This trait is a re-export of [`futures::io::AsyncWrite`] and is an async version of + [`std::io::Write`]. + + Methods other than [`poll_write`], [`poll_write_vectored`], [`poll_flush`], and + [`poll_close`] do not really exist in the trait itself, but they become available when + the prelude is imported: + + ``` + # #[allow(unused_imports)] + use async_std::prelude::*; + ``` + + [`std::io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + [`futures::io::AsyncWrite`]: + https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncWrite.html + [`poll_write`]: #tymethod.poll_write + [`poll_write_vectored`]: #method.poll_write_vectored + [`poll_flush`]: #tymethod.poll_flush + [`poll_close`]: #tymethod.poll_close + "#] pub trait Write [WriteExt: futures_io::AsyncWrite] { - /// Attempt to write bytes from `buf` into the object. + #[doc = r#" + Attempt to write bytes from `buf` into the object. + "#] fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll>; - /// Attempt to write bytes from `bufs` into the object using vectored - /// IO operations. + #[doc = r#" + Attempt to write bytes from `bufs` into the object using vectored IO operations. + "#] fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>] ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } - /// Attempt to flush the object, ensuring that any buffered data reach - /// their destination. + #[doc = r#" + Attempt to flush the object, ensuring that any buffered data reach + their destination. + "#] fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - /// Attempt to close the object. + #[doc = r#" + Attempt to close the object. + "#] fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; - /// Writes some bytes into the byte stream. - /// - /// Returns the number of bytes written from the start of the buffer. - /// - /// If the return value is `Ok(n)` then it must be guaranteed that - /// `0 <= n <= buf.len()`. A return value of `0` typically means that the underlying - /// object is no longer able to accept bytes and will likely not be able to in the - /// future as well, or that the buffer provided is empty. - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::prelude::*; - /// - /// let mut file = File::create("a.txt").await?; - /// - /// let n = file.write(b"hello world").await?; - /// # - /// # Ok(()) }) } - /// ``` - fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + 'a [WriteFuture<'a, Self>] + #[doc = r#" + Writes some bytes into the byte stream. + + Returns the number of bytes written from the start of the buffer. + + If the return value is `Ok(n)` then it must be guaranteed that + `0 <= n <= buf.len()`. A return value of `0` typically means that the underlying + object is no longer able to accept bytes and will likely not be able to in the + future as well, or that the buffer provided is empty. + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::prelude::*; + + let mut file = File::create("a.txt").await?; + + let n = file.write(b"hello world").await?; + # + # Ok(()) }) } + ``` + "#] + fn write<'a>( + &'a mut self, + buf: &'a [u8], + ) -> impl Future> + 'a [WriteFuture<'a, Self>] where Self: Unpin, { WriteFuture { writer: self, buf } } - /// Flushes the stream to ensure that all buffered contents reach their destination. - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::prelude::*; - /// - /// let mut file = File::create("a.txt").await?; - /// - /// file.write_all(b"hello world").await?; - /// file.flush().await?; - /// # - /// # Ok(()) }) } - /// ``` + #[doc = r#" + Flushes the stream to ensure that all buffered contents reach their destination. + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::prelude::*; + + let mut file = File::create("a.txt").await?; + + file.write_all(b"hello world").await?; + file.flush().await?; + # + # Ok(()) }) } + ``` + "#] fn flush(&mut self) -> impl Future> + '_ [FlushFuture<'_, Self>] where Self: Unpin, @@ -124,16 +140,18 @@ extension_trait! { FlushFuture { writer: self } } - /// Like [`write`], except that it writes from a slice of buffers. - /// - /// Data is copied from each buffer in order, with the final buffer read from possibly - /// being only partially consumed. This method must behave as a call to [`write`] with - /// the buffers concatenated would. - /// - /// The default implementation calls [`write`] with either the first nonempty buffer - /// provided, or an empty one if none exists. - /// - /// [`write`]: #tymethod.write + #[doc = r#" + Like [`write`], except that it writes from a slice of buffers. + + Data is copied from each buffer in order, with the final buffer read from possibly + being only partially consumed. This method must behave as a call to [`write`] with + the buffers concatenated would. + + The default implementation calls [`write`] with either the first nonempty buffer + provided, or an empty one if none exists. + + [`write`]: #tymethod.write + "#] fn write_vectored<'a>( &'a mut self, bufs: &'a [IoSlice<'a>], @@ -144,31 +162,36 @@ extension_trait! { WriteVectoredFuture { writer: self, bufs } } - /// Writes an entire buffer into the byte stream. - /// - /// This method will continuously call [`write`] until there is no more data to be - /// written or an error is returned. This method will not return until the entire - /// buffer has been successfully written or such an error occurs. - /// - /// [`write`]: #tymethod.write - /// - /// # Examples - /// - /// ```no_run - /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { - /// # - /// use async_std::fs::File; - /// use async_std::prelude::*; - /// - /// let mut file = File::create("a.txt").await?; - /// - /// file.write_all(b"hello world").await?; - /// # - /// # Ok(()) }) } - /// ``` - /// - /// [`write`]: #tymethod.write - fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + 'a [WriteAllFuture<'a, Self>] + #[doc = r#" + Writes an entire buffer into the byte stream. + + This method will continuously call [`write`] until there is no more data to be + written or an error is returned. This method will not return until the entire + buffer has been successfully written or such an error occurs. + + [`write`]: #tymethod.write + + # Examples + + ```no_run + # fn main() -> std::io::Result<()> { async_std::task::block_on(async { + # + use async_std::fs::File; + use async_std::prelude::*; + + let mut file = File::create("a.txt").await?; + + file.write_all(b"hello world").await?; + # + # Ok(()) }) } + ``` + + [`write`]: #tymethod.write + "#] + fn write_all<'a>( + &'a mut self, + buf: &'a [u8], + ) -> impl Future> + 'a [WriteAllFuture<'a, Self>] where Self: Unpin, { @@ -182,15 +205,15 @@ extension_trait! { cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -200,15 +223,15 @@ extension_trait! { cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -222,15 +245,15 @@ extension_trait! { cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -240,15 +263,15 @@ extension_trait! { cx: &mut Context<'_>, buf: &[u8], ) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } } diff --git a/src/os/unix/net/mod.rs b/src/os/unix/net/mod.rs index 465db54..a719a48 100644 --- a/src/os/unix/net/mod.rs +++ b/src/os/unix/net/mod.rs @@ -55,7 +55,7 @@ cfg_if! { /// assert_eq!(addr.is_unnamed(), true); /// ``` pub fn is_unnamed(&self) -> bool { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } /// Returns the contents of this address if it is a `pathname` address. @@ -84,13 +84,13 @@ cfg_if! { /// assert_eq!(addr.as_pathname(), None); /// ``` pub fn as_pathname(&self) -> Option<&Path> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } } else { diff --git a/src/stream/stream/mod.rs b/src/stream/stream/mod.rs index ba23718..c8731bc 100644 --- a/src/stream/stream/mod.rs +++ b/src/stream/stream/mod.rs @@ -89,25 +89,29 @@ cfg_if! { } extension_trait! { - /// An asynchronous stream of values. - /// - /// This trait is a re-export of [`futures::stream::Stream`] and is an async version of - /// [`std::iter::Iterator`]. - /// - /// The [provided methods] do not really exist in the trait itself, but they become - /// available when the prelude is imported: - /// - /// ``` - /// # #[allow(unused_imports)] - /// use async_std::prelude::*; - /// ``` - /// - /// [`std::iter::Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html - /// [`futures::stream::Stream`]: - /// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/stream/trait.Stream.html - /// [provided methods]: #provided-methods + #[doc = r#" + An asynchronous stream of values. + + This trait is a re-export of [`futures::stream::Stream`] and is an async version of + [`std::iter::Iterator`]. + + The [provided methods] do not really exist in the trait itself, but they become + available when the prelude is imported: + + ``` + # #[allow(unused_imports)] + use async_std::prelude::*; + ``` + + [`std::iter::Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html + [`futures::stream::Stream`]: + https://docs.rs/futures-preview/0.3.0-alpha.17/futures/stream/trait.Stream.html + [provided methods]: #provided-methods + "#] pub trait Stream [StreamExt: futures_core::stream::Stream] { - /// The type of items yielded by this stream. + #[doc = r#" + The type of items yielded by this stream. + "#] type Item; #[doc = r#" @@ -493,7 +497,10 @@ extension_trait! { # }) } ``` "#] - fn min_by(self, compare: F) -> impl Future> [MinByFuture] + fn min_by( + self, + compare: F, + )-> impl Future> [MinByFuture] where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, @@ -554,7 +561,10 @@ extension_trait! { # }) } ``` "#] - fn nth(&mut self, n: usize) -> impl Future> + '_ [NthFuture<'_, Self>] + fn nth( + &mut self, + n: usize, + ) -> impl Future> + '_ [NthFuture<'_, Self>] where Self: Sized, { @@ -607,7 +617,10 @@ extension_trait! { ``` "#] #[inline] - fn all(&mut self, f: F) -> impl Future + '_ [AllFuture<'_, Self, F, Self::Item>] + fn all( + &mut self, + f: F, + ) -> impl Future + '_ [AllFuture<'_, Self, F, Self::Item>] where Self: Unpin + Sized, F: FnMut(Self::Item) -> bool, @@ -658,7 +671,10 @@ extension_trait! { # }) } ``` "#] - fn find

(&mut self, p: P) -> impl Future> + '_ [FindFuture<'_, Self, P, Self::Item>] + fn find

( + &mut self, + p: P, + ) -> impl Future> + '_ [FindFuture<'_, Self, P, Self::Item>] where Self: Sized, P: FnMut(&Self::Item) -> bool, @@ -683,7 +699,10 @@ extension_trait! { # }) } ``` "#] - fn find_map(&mut self, f: F) -> impl Future> + '_ [FindMapFuture<'_, Self, F, Self::Item, B>] + fn find_map( + &mut self, + f: F, + ) -> impl Future> + '_ [FindMapFuture<'_, Self, F, Self::Item, B>] where Self: Sized, F: FnMut(Self::Item) -> Option, @@ -713,7 +732,11 @@ extension_trait! { # }) } ``` "#] - fn fold(self, init: B, f: F) -> impl Future [FoldFuture] + fn fold( + self, + init: B, + f: F, + ) -> impl Future [FoldFuture] where Self: Sized, F: FnMut(B, Self::Item) -> B, @@ -766,7 +789,10 @@ extension_trait! { ``` "#] #[inline] - fn any(&mut self, f: F) -> impl Future + '_ [AnyFuture<'_, Self, F, Self::Item>] + fn any( + &mut self, + f: F, + ) -> impl Future + '_ [AnyFuture<'_, Self, F, Self::Item>] where Self: Unpin + Sized, F: FnMut(Self::Item) -> bool, @@ -984,7 +1010,9 @@ extension_trait! { #[cfg(any(feature = "unstable", feature = "docs"))] #[cfg_attr(feature = "docs", doc(cfg(unstable)))] #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead (TODO)"] - fn collect<'a, B>(self) -> impl Future + 'a [Pin + 'a>>] + fn collect<'a, B>( + self, + ) -> impl Future + 'a [Pin + 'a>>] where Self: Sized + 'a, B: FromStream, @@ -997,7 +1025,7 @@ extension_trait! { type Item = S::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -1005,7 +1033,7 @@ extension_trait! { type Item = S::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -1017,7 +1045,7 @@ extension_trait! { type Item = <

::Target as Stream>::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -1025,7 +1053,7 @@ extension_trait! { type Item = T; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } @@ -1033,7 +1061,7 @@ extension_trait! { type Item = S::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - unreachable!() + unreachable!("this impl only appears in the rendered docs") } } } diff --git a/src/utils.rs b/src/utils.rs index 289c83e..bdf0f3b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -20,42 +20,77 @@ pub fn abort_on_panic(f: impl FnOnce() -> T) -> T { t } +/// Defines an extension trait for a base trait from the `futures` crate. +/// +/// In generated docs, the base trait will contain methods from the extension trait. In actual +/// code, the base trait will be re-exported and the extension trait will be hidden. We then +/// re-export the extension trait from the prelude. +/// +/// Inside invocations of this macro, we write a definitions that looks similar to the final +/// rendered docs, and the macro then generates all the boilerplate for us. #[doc(hidden)] #[macro_export] macro_rules! extension_trait { - (@gen ($($head:tt)*) pub trait $name:ident [$ext:ident: $orig:path] { $($body:tt)* } $($imp:item)*) => { + ( + // Interesting patterns: + // - `$name`: trait name that gets rendered in the docs + // - `$ext`: name of the hidden extension trait + // - `$base`: base trait from the `futures` crate + $(#[$attr:meta])* + pub trait $name:ident [$ext:ident: $base:path] { + $($body:tt)* + } + + // Shim trait impls that only appear in docs. + $($imp:item)* + ) => { + // A fake `impl Future` type that doesn't borrow. #[allow(dead_code)] mod owned { #[doc(hidden)] pub struct ImplFuture(std::marker::PhantomData); } + // A fake `impl Future` type that borrows its environment. #[allow(dead_code)] mod borrowed { #[doc(hidden)] pub struct ImplFuture<'a, T>(std::marker::PhantomData<&'a T>); } + // Render a fake trait containing all methods from the base trait and the extension trait. #[cfg(feature = "docs")] - $($head)* pub trait $name { + $(#[$attr])* + pub trait $name { extension_trait!(@doc () $($body)*); } + // When not rendering docs, re-export the base trait from the futures crate. #[cfg(not(feature = "docs"))] - pub use $orig as $name; + pub use $base as $name; - $($head)* pub trait $ext: $orig { + // The extension trait that adds methods to any type implementing the base trait. + $(#[$attr])* + pub trait $ext: $base { extension_trait!(@ext () $($body)*); } - impl $ext for T {} + // Blanket implementation of the extension trait for any type implementing the base trait. + impl $ext for T {} + // Shim trait impls that only appear in docs. $(#[cfg(feature = "docs")] $imp)* }; - (@gen ($($head:tt)*) $token:tt $($tail:tt)*) => { - extension_trait!(@gen ($($head)* $token) $($tail)*); + + // Parse an associated type. + (@doc ($($head:tt)*) type $name:ident; $($tail:tt)*) => { + extension_trait!(@doc ($($head)* type $name;) $($tail)*); + }; + (@ext ($($head:tt)*) type $ident:ty; $($tail:tt)*) => { + extension_trait!(@ext ($($head)*) $($tail)*); }; + // Parse a required method. (@doc ($($head:tt)*) fn $name:ident $args:tt $(-> $ret:ty)?; $($tail:tt)*) => { extension_trait!(@doc ($($head)* fn $name $args $(-> $ret)?;) $($tail)*); }; @@ -63,6 +98,7 @@ macro_rules! extension_trait { extension_trait!(@ext ($($head)*) $($tail)*); }; + // Parse a provided method that exists in the base trait. (@doc ($($head:tt)*) fn $name:ident $args:tt $(-> $ret:ty)? { $($body:tt)* } $($tail:tt)*) => { extension_trait!(@doc ($($head)* fn $name $args $(-> $ret)? { $($body)* }) $($tail)*); }; @@ -70,13 +106,7 @@ macro_rules! extension_trait { extension_trait!(@ext ($($head)*) $($tail)*); }; - (@doc ($($head:tt)*) type $name:ident; $($tail:tt)*) => { - extension_trait!(@doc ($($head)* type $name;) $($tail)*); - }; - (@ext ($($head:tt)*) type $ident:ty; $($tail:tt)*) => { - extension_trait!(@ext ($($head)*) $($tail)*); - }; - + // Parse the return type in an extension method where the future doesn't borrow. (@doc ($($head:tt)*) -> impl Future [$f:ty] $($tail:tt)*) => { extension_trait!(@doc ($($head)* -> owned::ImplFuture<$out>) $($tail)*); }; @@ -84,6 +114,7 @@ macro_rules! extension_trait { extension_trait!(@ext ($($head)* -> $f) $($tail)*); }; + // Parse the return type in an extension method where the future borrows its environment. (@doc ($($head:tt)*) -> impl Future + $lt:lifetime [$f:ty] $($tail:tt)*) => { extension_trait!(@doc ($($head)* -> borrowed::ImplFuture<$lt, $out>) $($tail)*); }; @@ -91,6 +122,7 @@ macro_rules! extension_trait { extension_trait!(@ext ($($head)* -> $f) $($tail)*); }; + // Parse a token that doesn't fit into any of the previous patterns. (@doc ($($head:tt)*) $token:tt $($tail:tt)*) => { extension_trait!(@doc ($($head)* $token) $($tail)*); }; @@ -98,10 +130,9 @@ macro_rules! extension_trait { extension_trait!(@ext ($($head)* $token) $($tail)*); }; + // Handle the end of the token list. (@doc ($($head:tt)*)) => { $($head)* }; (@ext ($($head:tt)*)) => { $($head)* }; - - ($($head:tt)*) => { extension_trait!(@gen () $($head)*); }; } pub use crate::extension_trait;