async_peek/lib.rs
1/**************************************************************************************************
2 * *
3 * This Source Code Form is subject to the terms of the Mozilla Public *
4 * License, v. 2.0. If a copy of the MPL was not distributed with this *
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. *
6 * *
7 **************************************************************************************************/
8
9// ======================================== Documentation ======================================= \\
10
11//! This crate provides [`AsyncPeek`], a trait to read data asynchronously without removing it
12//! from the queue (like when using the blocking methods [`std::net::TcpStream::peek()`] and
13//! [`std::net::UdpSocket::peek()`]).
14
15// =========================================== Imports ========================================== \\
16
17use cfg_if::cfg_if;
18use core::cmp;
19use core::future::Future;
20use core::ops::{Deref, DerefMut};
21use core::pin::Pin;
22use core::task::{Context, Poll};
23use std::io::Error;
24
25#[cfg(feature = "async-io")]
26use std::net::{TcpStream, UdpSocket};
27
28// ========================================= Interfaces ========================================= \\
29
30/// Read data asynchronously without removing it from the queue.
31pub trait AsyncPeek {
32 /// Attempts to read data into `buf` without removing it from the queue.
33 ///
34 /// Returns the number of bytes read on success, or [`io::Error`] if an error is encountered.
35 ///
36 /// If no data is available, the current task is registered to be notified when data becomes
37 /// available or the stream is closed, and `Poll::Pending` is returned.
38 ///
39 /// [`io::Error`]: std::io::Error
40 fn poll_peek(
41 self: Pin<&mut Self>,
42 ctx: &mut Context,
43 buf: &mut [u8],
44 ) -> Poll<Result<usize, Error>>;
45}
46
47/// An extension trait which adds utility methods to [`AsyncPeek`] types.
48pub trait AsyncPeekExt: AsyncPeek {
49 /// Tries to read data into `buf` without removing it from the queue.
50 ///
51 /// Returns the number of bytes read, or [`io::Error`] if an error is encountered.
52 ///
53 /// ## Examples
54 ///
55 /// ```rust
56 /// # smol::block_on(async {
57 /// #
58 /// use async_peek::{AsyncPeek, AsyncPeekExt};
59 /// use smol::Async;
60 /// use std::net::{TcpStream, ToSocketAddrs};
61 ///
62 /// let addr = "127.0.0.1:0".to_socket_addrs()?.next().unwrap();
63 /// let mut stream = Async::<TcpStream>::connect(addr).await?;
64 /// let mut buf = [0; 64];
65 ///
66 /// let n = stream.peek(&mut buf).await?;
67 /// println!("Peeked {} bytes", n);
68 /// #
69 /// # std::io::Result::Ok(()) });
70 /// ```
71 ///
72 /// [`io::Error`]: std::io::Error
73 fn peek<'peek>(&'peek mut self, buf: &'peek mut [u8]) -> Peek<'peek, Self>
74 where
75 Self: Unpin,
76 {
77 Peek { peek: self, buf }
78 }
79}
80
81// ============================================ Types =========================================== \\
82
83/// Future for the [`peek()`] function.
84///
85/// [`peek()`]: AsyncPeekExt::peek()
86pub struct Peek<'peek, P: ?Sized> {
87 peek: &'peek mut P,
88 buf: &'peek mut [u8],
89}
90
91// ======================================== macro_rules! ======================================== \\
92
93#[allow(unused)]
94macro_rules! impl_for_net {
95 ($net:ty) => {
96 impl AsyncPeek for $net {
97 fn poll_peek(
98 self: Pin<&mut Self>,
99 ctx: &mut Context,
100 buf: &mut [u8],
101 ) -> Poll<Result<usize, Error>> {
102 let fut = (&*self).peek(buf);
103 ufut::pin!(fut);
104
105 fut.poll(ctx)
106 }
107 }
108 };
109}
110
111// ======================================= impl AsyncPeek ======================================= \\
112
113impl AsyncPeek for &[u8] {
114 fn poll_peek(
115 self: Pin<&mut Self>,
116 _: &mut Context,
117 buf: &mut [u8],
118 ) -> Poll<Result<usize, Error>> {
119 let len = cmp::min(buf.len(), self.len());
120 buf[0..len].copy_from_slice(&self[0..len]);
121
122 Poll::Ready(Ok(len))
123 }
124}
125
126impl<T> AsyncPeek for &mut T
127where
128 T: AsyncPeek + Unpin + ?Sized,
129{
130 fn poll_peek(
131 mut self: Pin<&mut Self>,
132 ctx: &mut Context,
133 buf: &mut [u8],
134 ) -> Poll<Result<usize, Error>> {
135 Pin::new(&mut **self).poll_peek(ctx, buf)
136 }
137}
138
139impl<T> AsyncPeek for Box<T>
140where
141 T: AsyncPeek + Unpin + ?Sized,
142{
143 fn poll_peek(
144 mut self: Pin<&mut Self>,
145 ctx: &mut Context,
146 buf: &mut [u8],
147 ) -> Poll<Result<usize, Error>> {
148 Pin::new(&mut **self).poll_peek(ctx, buf)
149 }
150}
151
152impl<T> AsyncPeek for Pin<T>
153where
154 T: DerefMut + Unpin,
155 <T as Deref>::Target: AsyncPeek,
156{
157 fn poll_peek(
158 self: Pin<&mut Self>,
159 ctx: &mut Context,
160 buf: &mut [u8],
161 ) -> Poll<Result<usize, Error>> {
162 self.get_mut().as_mut().poll_peek(ctx, buf)
163 }
164}
165
166
167
168cfg_if! {
169 if #[cfg(feature = "async-io")] {
170 impl_for_net!(async_io::Async<TcpStream>);
171 impl_for_net!(async_io::Async<UdpSocket>);
172 impl_for_net!(&async_io::Async<TcpStream>);
173 impl_for_net!(&async_io::Async<UdpSocket>);
174 }
175}
176
177cfg_if! {
178 if #[cfg(feature = "async-net")] {
179 impl_for_net!(async_net::TcpStream);
180 impl_for_net!(async_net::UdpSocket);
181 impl_for_net!(&async_net::TcpStream);
182 impl_for_net!(&async_net::UdpSocket);
183 }
184}
185
186// ====================================== impl AsyncPeekExt ===================================== \\
187
188impl<P: AsyncPeek + ?Sized> AsyncPeekExt for P {}
189
190// ========================================= impl Future ======================================== \\
191
192impl<P: AsyncPeek + Unpin> Future for Peek<'_, P> {
193 type Output = Result<usize, Error>;
194
195 fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
196 let this = &mut *self;
197 Pin::new(&mut this.peek).poll_peek(ctx, this.buf)
198 }
199}