1#![cfg_attr(feature = "fail-on-warnings", deny(warnings))]
31#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
32#![allow(clippy::multiple_crate_versions)]
33
34use std::{marker::PhantomData, net::SocketAddr};
35
36use ::tokio::io::{AsyncRead, AsyncWrite};
37use async_trait::async_trait;
38use thiserror::Error;
39
40#[cfg(feature = "tokio")]
45pub mod tokio;
46
47#[cfg(feature = "simulator")]
52pub mod simulator;
53
54#[derive(Debug, Error)]
56pub enum Error {
57 #[error(transparent)]
59 IO(#[from] ::std::io::Error),
60 #[error(transparent)]
62 AddrParse(#[from] ::std::net::AddrParseError),
63 #[error(transparent)]
65 ParseInt(#[from] std::num::ParseIntError),
66 #[cfg(feature = "simulator")]
68 #[error("Send error")]
69 Send,
70}
71
72#[async_trait]
78pub trait GenericTcpListener<T>: Send + Sync {
79 async fn accept(&self) -> Result<(T, SocketAddr), Error>;
87}
88
89pub trait GenericTcpStream<R: GenericTcpStreamReadHalf, W: GenericTcpStreamWriteHalf>:
94 AsyncRead + AsyncWrite + Send + Sync + Unpin
95{
96 fn into_split(self) -> (R, W);
98
99 fn local_addr(&self) -> std::io::Result<SocketAddr>;
105
106 fn peer_addr(&self) -> std::io::Result<SocketAddr>;
112}
113
114pub trait GenericTcpStreamReadHalf: AsyncRead + Send + Sync + Unpin {}
118
119pub trait GenericTcpStreamWriteHalf: AsyncWrite + Send + Sync + Unpin {}
123
124pub struct TcpListenerWrapper<
130 R: GenericTcpStreamReadHalf,
131 W: GenericTcpStreamWriteHalf,
132 S: GenericTcpStream<R, W>,
133 T: GenericTcpListener<S>,
134>(T, PhantomData<R>, PhantomData<W>, PhantomData<S>);
135
136pub struct TcpStreamWrapper<
142 R: GenericTcpStreamReadHalf,
143 W: GenericTcpStreamWriteHalf,
144 T: GenericTcpStream<R, W>,
145>(T, PhantomData<R>, PhantomData<W>);
146
147#[allow(unused)]
148macro_rules! impl_http {
149 ($module:ident, $local_module:ident $(,)?) => {
150 paste::paste! {
151 pub use [< impl_ $module >]::*;
152 }
153
154 mod $local_module {
155 use std::pin::pin;
156
157 use crate::*;
158
159 paste::paste! {
160 #[doc = concat!("Read half of a ", stringify!($module), " TCP stream.\n\nWraps the underlying read half to provide a generic interface.")]
161 pub type [< $module:camel TcpStreamReadHalf >] = $module::TcpStreamReadHalf;
162 type ModuleTcpStreamReadHalf = [< $module:camel TcpStreamReadHalf >];
163
164 #[doc = concat!("Write half of a ", stringify!($module), " TCP stream.\n\nWraps the underlying write half to provide a generic interface.")]
165 pub type [< $module:camel TcpStreamWriteHalf >] = $module::TcpStreamWriteHalf;
166 type ModuleTcpStreamWriteHalf = [< $module:camel TcpStreamWriteHalf >];
167
168 #[doc = concat!("TCP stream for ", stringify!($module), ".\n\nWraps the underlying stream to provide a generic interface that can be split into read and write halves.")]
169 pub type [< $module:camel TcpStream >] = TcpStreamWrapper<ModuleTcpStreamReadHalf, ModuleTcpStreamWriteHalf, $module::TcpStream>;
170 type ModuleTcpStream = [< $module:camel TcpStream >];
171
172 #[doc = concat!("TCP listener for ", stringify!($module), ".\n\nWraps the underlying listener to provide a generic interface for accepting connections.")]
173 pub type [< $module:camel TcpListener >] = TcpListenerWrapper<ModuleTcpStreamReadHalf, ModuleTcpStreamWriteHalf, ModuleTcpStream, $module::TcpListener>;
174 type ModuleTcpListener = [< $module:camel TcpListener >];
175 }
176
177 #[async_trait]
178 impl GenericTcpListener<ModuleTcpStream> for ModuleTcpListener {
179 async fn accept(&self) -> Result<(ModuleTcpStream, SocketAddr), Error> {
180 self.0.accept().await
181 }
182 }
183
184 impl GenericTcpStream<ModuleTcpStreamReadHalf, ModuleTcpStreamWriteHalf> for ModuleTcpStream {
185 fn into_split(self) -> (ModuleTcpStreamReadHalf, ModuleTcpStreamWriteHalf) {
186 self.0.into_split()
187 }
188
189 fn local_addr(&self) -> std::io::Result<SocketAddr> {
190 self.0.local_addr()
191 }
192
193 fn peer_addr(&self) -> std::io::Result<SocketAddr> {
194 self.0.peer_addr()
195 }
196 }
197
198 impl ModuleTcpStream {
199 pub async fn connect(addr: &str) -> std::io::Result<Self> {
205 Ok(Self($module::TcpStream::connect(addr).await?, PhantomData, PhantomData))
206 }
207
208 pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
214 self.0.local_addr()
215 }
216
217 pub fn peer_addr(&self) -> std::io::Result<SocketAddr> {
223 self.0.peer_addr()
224 }
225 }
226
227 impl AsyncRead for ModuleTcpStream {
228 fn poll_read(
229 self: std::pin::Pin<&mut Self>,
230 cx: &mut std::task::Context<'_>,
231 buf: &mut ::tokio::io::ReadBuf<'_>,
232 ) -> std::task::Poll<std::io::Result<()>> {
233 let this = self.get_mut();
234 let inner = &mut this.0;
235 let inner = pin!(inner);
236 AsyncRead::poll_read(inner, cx, buf)
237 }
238 }
239
240 impl AsyncWrite for ModuleTcpStream {
241 fn poll_write(
242 self: std::pin::Pin<&mut Self>,
243 cx: &mut std::task::Context<'_>,
244 buf: &[u8],
245 ) -> std::task::Poll<Result<usize, std::io::Error>> {
246 let this = self.get_mut();
247 let inner = &mut this.0;
248 let inner = pin!(inner);
249 AsyncWrite::poll_write(inner, cx, buf)
250 }
251
252 fn poll_flush(
253 self: std::pin::Pin<&mut Self>,
254 cx: &mut std::task::Context<'_>,
255 ) -> std::task::Poll<Result<(), std::io::Error>> {
256 let this = self.get_mut();
257 let inner = &mut this.0;
258 let inner = pin!(inner);
259 AsyncWrite::poll_flush(inner, cx)
260 }
261
262 fn poll_shutdown(
263 self: std::pin::Pin<&mut Self>,
264 cx: &mut std::task::Context<'_>,
265 ) -> std::task::Poll<Result<(), std::io::Error>> {
266 let this = self.get_mut();
267 let inner = &mut this.0;
268 let inner = pin!(inner);
269 AsyncWrite::poll_shutdown(inner, cx)
270 }
271 }
272 }
273 };
274}
275
276#[cfg(feature = "simulator")]
277impl_http!(simulator, impl_simulator);
278
279#[cfg(feature = "tokio")]
280impl_http!(tokio, impl_tokio);
281
282#[allow(unused)]
283macro_rules! impl_gen_types {
284 ($module:ident $(,)?) => {
285 paste::paste! {
286 pub type TcpListener = [< $module:camel TcpListener >];
292
293 pub type TcpStream = [< $module:camel TcpStream >];
299
300 pub type TcpStreamReadHalf = [< $module:camel TcpStreamReadHalf >];
306
307 pub type TcpStreamWriteHalf = [< $module:camel TcpStreamWriteHalf >];
313 }
314 };
315}
316
317#[cfg(feature = "simulator")]
318impl_gen_types!(simulator);
319
320#[cfg(all(not(feature = "simulator"), feature = "tokio"))]
321impl_gen_types!(tokio);
322
323#[allow(unused)]
324macro_rules! impl_read_inner {
325 ($type:ty $(,)?) => {
326 impl tokio::io::AsyncRead for $type {
327 fn poll_read(
328 self: std::pin::Pin<&mut Self>,
329 cx: &mut std::task::Context<'_>,
330 buf: &mut ::tokio::io::ReadBuf<'_>,
331 ) -> std::task::Poll<std::io::Result<()>> {
332 let this = self.get_mut();
333 let inner = &mut this.0;
334 let inner = std::pin::pin!(inner);
335 tokio::io::AsyncRead::poll_read(inner, cx, buf)
336 }
337 }
338 };
339}
340
341#[allow(unused)]
342macro_rules! impl_write_inner {
343 ($type:ty $(,)?) => {
344 impl tokio::io::AsyncWrite for $type {
345 fn poll_write(
346 self: std::pin::Pin<&mut Self>,
347 cx: &mut std::task::Context<'_>,
348 buf: &[u8],
349 ) -> std::task::Poll<Result<usize, std::io::Error>> {
350 let this = self.get_mut();
351 let inner = &mut this.0;
352 let inner = std::pin::pin!(inner);
353 tokio::io::AsyncWrite::poll_write(inner, cx, buf)
354 }
355
356 fn poll_flush(
357 self: std::pin::Pin<&mut Self>,
358 cx: &mut std::task::Context<'_>,
359 ) -> std::task::Poll<Result<(), std::io::Error>> {
360 let this = self.get_mut();
361 let inner = &mut this.0;
362 let inner = std::pin::pin!(inner);
363 tokio::io::AsyncWrite::poll_flush(inner, cx)
364 }
365
366 fn poll_shutdown(
367 self: std::pin::Pin<&mut Self>,
368 cx: &mut std::task::Context<'_>,
369 ) -> std::task::Poll<Result<(), std::io::Error>> {
370 let this = self.get_mut();
371 let inner = &mut this.0;
372 let inner = std::pin::pin!(inner);
373 tokio::io::AsyncWrite::poll_shutdown(inner, cx)
374 }
375 }
376 };
377}
378
379#[allow(unused)]
380pub(crate) use impl_read_inner;
381#[allow(unused)]
382pub(crate) use impl_write_inner;