gimbal_tcp/
lib.rs

1#![cfg_attr(feature = "fail-on-warnings", deny(warnings))]
2#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
3#![allow(clippy::multiple_crate_versions)]
4
5use std::{marker::PhantomData, net::SocketAddr};
6
7use ::tokio::io::{AsyncRead, AsyncWrite};
8use async_trait::async_trait;
9use thiserror::Error;
10
11#[cfg(feature = "tokio")]
12pub mod tokio;
13
14#[cfg(feature = "simulator")]
15pub mod simulator;
16
17#[derive(Debug, Error)]
18pub enum Error {
19    #[error(transparent)]
20    IO(#[from] ::std::io::Error),
21}
22
23#[async_trait]
24pub trait GenericTcpListener<T>: Send + Sync {
25    async fn accept(&self) -> Result<(T, SocketAddr), Error>;
26}
27
28pub trait GenericTcpStream<R: GenericTcpStreamReadHalf, W: GenericTcpStreamWriteHalf>:
29    AsyncRead + AsyncWrite + Send + Sync + Unpin
30{
31    fn into_split(self) -> (R, W);
32}
33pub trait GenericTcpStreamReadHalf: AsyncRead + Send + Sync + Unpin {}
34pub trait GenericTcpStreamWriteHalf: AsyncWrite + Send + Sync + Unpin {}
35
36pub struct TcpListenerWrapper<
37    R: GenericTcpStreamReadHalf,
38    W: GenericTcpStreamWriteHalf,
39    S: GenericTcpStream<R, W>,
40    T: GenericTcpListener<S>,
41>(T, PhantomData<R>, PhantomData<W>, PhantomData<S>);
42pub struct TcpStreamWrapper<
43    R: GenericTcpStreamReadHalf,
44    W: GenericTcpStreamWriteHalf,
45    T: GenericTcpStream<R, W>,
46>(T, PhantomData<R>, PhantomData<W>);
47
48#[allow(unused)]
49macro_rules! impl_http {
50    ($module:ident, $local_module:ident $(,)?) => {
51        paste::paste! {
52            pub use [< impl_ $module >]::*;
53        }
54
55        mod $local_module {
56            use std::pin::pin;
57
58            use crate::*;
59
60            paste::paste! {
61                pub type [< $module:camel TcpStreamReadHalf >] = $module::TcpStreamReadHalf;
62                type ModuleTcpStreamReadHalf = [< $module:camel TcpStreamReadHalf >];
63
64                pub type [< $module:camel TcpStreamWriteHalf >] = $module::TcpStreamWriteHalf;
65                type ModuleTcpStreamWriteHalf = [< $module:camel TcpStreamWriteHalf >];
66
67                pub type [< $module:camel TcpStream >] = TcpStreamWrapper<ModuleTcpStreamReadHalf, ModuleTcpStreamWriteHalf, $module::TcpStream>;
68                type ModuleTcpStream = [< $module:camel TcpStream >];
69
70                pub type [< $module:camel TcpListener >] = TcpListenerWrapper<ModuleTcpStreamReadHalf, ModuleTcpStreamWriteHalf, ModuleTcpStream, $module::TcpListener>;
71                type ModuleTcpListener = [< $module:camel TcpListener >];
72            }
73
74            #[async_trait]
75            impl GenericTcpListener<ModuleTcpStream> for ModuleTcpListener {
76                async fn accept(&self) -> Result<(ModuleTcpStream, SocketAddr), Error> {
77                    self.0.accept().await
78                }
79            }
80
81            impl GenericTcpStream<ModuleTcpStreamReadHalf, ModuleTcpStreamWriteHalf> for ModuleTcpStream {
82                fn into_split(self) -> (ModuleTcpStreamReadHalf, ModuleTcpStreamWriteHalf) {
83                    self.0.into_split()
84                }
85            }
86
87            impl AsyncRead for ModuleTcpStream {
88                fn poll_read(
89                    self: std::pin::Pin<&mut Self>,
90                    cx: &mut std::task::Context<'_>,
91                    buf: &mut ::tokio::io::ReadBuf<'_>,
92                ) -> std::task::Poll<std::io::Result<()>> {
93                    let this = self.get_mut();
94                    let inner = &mut this.0;
95                    let inner = pin!(inner);
96                    AsyncRead::poll_read(inner, cx, buf)
97                }
98            }
99
100            impl AsyncWrite for ModuleTcpStream {
101                fn poll_write(
102                    self: std::pin::Pin<&mut Self>,
103                    cx: &mut std::task::Context<'_>,
104                    buf: &[u8],
105                ) -> std::task::Poll<Result<usize, std::io::Error>> {
106                    let this = self.get_mut();
107                    let inner = &mut this.0;
108                    let inner = pin!(inner);
109                    AsyncWrite::poll_write(inner, cx, buf)
110                }
111
112                fn poll_flush(
113                    self: std::pin::Pin<&mut Self>,
114                    cx: &mut std::task::Context<'_>,
115                ) -> std::task::Poll<Result<(), std::io::Error>> {
116                    let this = self.get_mut();
117                    let inner = &mut this.0;
118                    let inner = pin!(inner);
119                    AsyncWrite::poll_flush(inner, cx)
120                }
121
122                fn poll_shutdown(
123                    self: std::pin::Pin<&mut Self>,
124                    cx: &mut std::task::Context<'_>,
125                ) -> std::task::Poll<Result<(), std::io::Error>> {
126                    let this = self.get_mut();
127                    let inner = &mut this.0;
128                    let inner = pin!(inner);
129                    AsyncWrite::poll_shutdown(inner, cx)
130                }
131            }
132        }
133    };
134}
135
136#[cfg(feature = "simulator")]
137impl_http!(simulator, impl_simulator);
138
139#[cfg(feature = "tokio")]
140impl_http!(tokio, impl_tokio);
141
142#[allow(unused)]
143macro_rules! impl_gen_types {
144    ($module:ident $(,)?) => {
145        paste::paste! {
146            pub type TcpListener = [< $module:camel TcpListener >];
147            pub type TcpStream = [< $module:camel TcpStream >];
148            pub type TcpStreamReadHalf = [< $module:camel TcpStreamReadHalf >];
149            pub type TcpStreamWriteHalf = [< $module:camel TcpStreamWriteHalf >];
150        }
151    };
152}
153
154#[cfg(feature = "simulator")]
155impl_gen_types!(simulator);
156
157#[cfg(all(not(feature = "simulator"), feature = "tokio"))]
158impl_gen_types!(tokio);
159
160#[allow(unused)]
161macro_rules! impl_read_inner {
162    ($type:ty $(,)?) => {
163        impl tokio::io::AsyncRead for $type {
164            fn poll_read(
165                self: std::pin::Pin<&mut Self>,
166                cx: &mut std::task::Context<'_>,
167                buf: &mut ::tokio::io::ReadBuf<'_>,
168            ) -> std::task::Poll<std::io::Result<()>> {
169                let this = self.get_mut();
170                let inner = &mut this.0;
171                let inner = std::pin::pin!(inner);
172                tokio::io::AsyncRead::poll_read(inner, cx, buf)
173            }
174        }
175    };
176}
177
178#[allow(unused)]
179macro_rules! impl_write_inner {
180    ($type:ty $(,)?) => {
181        impl tokio::io::AsyncWrite for $type {
182            fn poll_write(
183                self: std::pin::Pin<&mut Self>,
184                cx: &mut std::task::Context<'_>,
185                buf: &[u8],
186            ) -> std::task::Poll<Result<usize, std::io::Error>> {
187                let this = self.get_mut();
188                let inner = &mut this.0;
189                let inner = std::pin::pin!(inner);
190                tokio::io::AsyncWrite::poll_write(inner, cx, buf)
191            }
192
193            fn poll_flush(
194                self: std::pin::Pin<&mut Self>,
195                cx: &mut std::task::Context<'_>,
196            ) -> std::task::Poll<Result<(), std::io::Error>> {
197                let this = self.get_mut();
198                let inner = &mut this.0;
199                let inner = std::pin::pin!(inner);
200                tokio::io::AsyncWrite::poll_flush(inner, cx)
201            }
202
203            fn poll_shutdown(
204                self: std::pin::Pin<&mut Self>,
205                cx: &mut std::task::Context<'_>,
206            ) -> std::task::Poll<Result<(), std::io::Error>> {
207                let this = self.get_mut();
208                let inner = &mut this.0;
209                let inner = std::pin::pin!(inner);
210                tokio::io::AsyncWrite::poll_shutdown(inner, cx)
211            }
212        }
213    };
214}
215
216#[allow(unused)]
217pub(crate) use impl_read_inner;
218#[allow(unused)]
219pub(crate) use impl_write_inner;