1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use core::future::Future;
use no_std_net::SocketAddr;

/// This trait is implemented by TCP/IP stacks. You could, for example, have an implementation
/// which knows how to send AT commands to an ESP8266 WiFi module. You could have another implementation
/// which knows how to driver the Rust Standard Library's `std::net` module. Given this trait, you can
/// write a portable HTTP client which can work with either implementation.
pub trait TcpClientStack {
	/// The type returned when we create a new TCP socket
	type TcpSocket;
	/// The type returned when we have an error
	type Error: core::fmt::Debug;

	/// Future returned by `socket` function.
	type SocketFuture<'m>: Future<Output = Result<Self::TcpSocket, Self::Error>> + 'm
	where
		Self: 'm;

	/// Open a socket for usage as a TCP client.
	///
	/// The socket must be connected before it can be used.
	///
	/// Returns `Ok(socket)` if the socket was successfully created.
	fn socket<'m>(&'m mut self) -> Self::SocketFuture<'m>;

	/// Future returned by `connect` function.
	type ConnectFuture<'m>: Future<Output = Result<(), Self::Error>> + 'm
	where
		Self: 'm;

	/// Connect to the given remote host and port.
	///
	/// Returns `Ok` if the connection was successful.
	fn connect<'m>(
		&'m mut self,
		socket: &'m mut Self::TcpSocket,
		remote: SocketAddr,
	) -> Self::ConnectFuture<'m>;

	/// Future returned by `is_connected` function.
	type IsConnectedFuture<'m>: Future<Output = Result<bool, Self::Error>> + 'm
	where
		Self: 'm;

	/// Check if this socket is connected
	fn is_connected<'m>(&'m mut self, socket: &'m Self::TcpSocket) -> Self::IsConnectedFuture<'m>;

	/// Future returned by `send` function.
	type SendFuture<'m>: Future<Output = Result<usize, Self::Error>> + 'm
	where
		Self: 'm;

	/// Write to the stream.
	///
	/// Returns the number of bytes written (which may be less than `buffer.len()`) or an error.
	fn send<'m>(
		&'m mut self,
		socket: &'m mut Self::TcpSocket,
		buffer: &'m [u8],
	) -> Self::SendFuture<'m>;

	/// Future returned by `receive` function.
	type ReceiveFuture<'m>: Future<Output = Result<usize, Self::Error>> + 'm
	where
		Self: 'm;

	/// Receive data from the stream.
	///
	/// Returns `Ok(n)`, which means `n` bytes of data have been received and
	/// they have been placed in `&buffer[0..n]`, or an error.
	fn receive<'m>(
		&'m mut self,
		socket: &'m mut Self::TcpSocket,
		buffer: &'m mut [u8],
	) -> Self::ReceiveFuture<'m>;

	/// Future returned by `close` function.
	type CloseFuture<'m>: Future<Output = Result<(), Self::Error>> + 'm
	where
		Self: 'm;

	/// Close an existing TCP socket.
	fn close<'m>(&'m mut self, socket: Self::TcpSocket) -> Self::CloseFuture<'m>;
}

/// This trait is implemented by TCP/IP stacks that expose TCP server functionality. TCP servers
/// may listen for connection requests to establish multiple unique TCP connections with various
/// clients.
pub trait TcpFullStack: TcpClientStack {
	/// Future returned by `bind` function.
	type BindFuture<'m>: Future<Output = Result<(), Self::Error>> + 'm
	where
		Self: 'm;
	/// Create a new TCP socket and bind it to the specified local port.
	///
	/// Returns `Ok` when a socket is successfully bound to the specified local port. Otherwise, an
	/// `Err(e)` variant is returned.
	fn bind<'m>(
		&'m mut self,
		socket: &'m mut Self::TcpSocket,
		local_port: u16,
	) -> Self::BindFuture<'m>;

	/// Future returned by `listen` function.
	type ListenFuture<'m>: Future<Output = Result<(), Self::Error>> + 'm
	where
		Self: 'm;

	/// Begin listening for connection requests on a previously-bound socket.
	///
	/// Returns `Ok` if the socket was successfully transitioned to the listening state. Otherwise,
	/// an `Err(e)` variant is returned.
	fn listen<'m>(&'m mut self, socket: &'m mut Self::TcpSocket) -> Self::ListenFuture<'m>;

	/// Future returned by `accept` function.
	type AcceptFuture<'m>: Future<Output = Result<(Self::TcpSocket, SocketAddr), Self::Error>> + 'm
	where
		Self: 'm;

	/// Accept an active connection request on a listening socket.
	///
	/// Returns `Ok(connection)` if a new connection was created. If no pending connections are
	/// available, this function should return [`nb::Error::WouldBlock`].
	fn accept<'m>(&'m mut self, socket: &'m mut Self::TcpSocket) -> Self::AcceptFuture<'m>;
}

impl<T: TcpClientStack> TcpClientStack for &mut T {
	type Error = T::Error;
	type TcpSocket = T::TcpSocket;

	type SocketFuture<'m> = T::SocketFuture<'m> where Self: 'm;
	fn socket<'m>(&'m mut self) -> Self::SocketFuture<'m> {
		T::socket(self)
	}

	type ConnectFuture<'m> = T::ConnectFuture<'m> where Self: 'm;
	fn connect<'m>(
		&'m mut self,
		socket: &'m mut Self::TcpSocket,
		remote: SocketAddr,
	) -> Self::ConnectFuture<'m> {
		T::connect(self, socket, remote)
	}

	type IsConnectedFuture<'m> = T::IsConnectedFuture<'m> where Self: 'm;
	fn is_connected<'m>(&'m mut self, socket: &'m Self::TcpSocket) -> Self::IsConnectedFuture<'m> {
		T::is_connected(self, socket)
	}

	type SendFuture<'m> = T::SendFuture<'m> where Self: 'm;
	fn send<'m>(
		&'m mut self,
		socket: &'m mut Self::TcpSocket,
		buffer: &'m [u8],
	) -> Self::SendFuture<'m> {
		T::send(self, socket, buffer)
	}

	type ReceiveFuture<'m> = T::ReceiveFuture<'m> where Self: 'm;
	fn receive<'m>(
		&'m mut self,
		socket: &'m mut Self::TcpSocket,
		buffer: &'m mut [u8],
	) -> Self::ReceiveFuture<'m> {
		T::receive(self, socket, buffer)
	}

	type CloseFuture<'m> = T::CloseFuture<'m> where Self: 'm;
	fn close<'m>(&'m mut self, socket: Self::TcpSocket) -> Self::CloseFuture<'m> {
		T::close(self, socket)
	}
}