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
use core::future::Future;
use no_std_net::SocketAddr;

/// This trait is implemented by UDP/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 how
/// write a portable CoAP client which can work with either implementation.
pub trait UdpClientStack {
	/// The type returned when we create a new UDP socket
	type UdpSocket;
	/// 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::UdpSocket, Self::Error>> + 'm
	where
		Self: 'm;

	/// Open a socket for usage as a UDP client.
	///
	/// 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 a UDP socket with a peer using a dynamically selected port.
	///
	/// Selects a port number automatically and initializes for read/writing.
	fn connect<'m>(
		&'m mut self,
		socket: &'m mut Self::UdpSocket,
		remote: SocketAddr,
	) -> Self::ConnectFuture<'m>;

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

	/// Send a datagram to the remote host.
	///
	/// The remote host used is either the one specified in `UdpStack::connect`
	/// or the last one used in `UdpServerStack::write_to`.
	fn send<'m>(
		&'m mut self,
		socket: &'m mut Self::UdpSocket,
		buffer: &'m [u8],
	) -> Self::SendFuture<'m>;

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

	/// Read a datagram the remote host has sent to us.
	///
	/// Returns `Ok((n, remote))`, which means a datagram of size `n` has been
	/// received from `remote` and been placed in `&buffer[0..n]`, or an error.
	/// If a packet has not been received when called, then [`nb::Error::WouldBlock`]
	/// should be returned.
	fn receive<'m>(
		&'m mut self,
		socket: &'m mut Self::UdpSocket,
		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 UDP socket.
	fn close<'m>(&'m mut self, socket: Self::UdpSocket) -> Self::CloseFuture<'m>;
}

/// This trait is implemented by UDP/IP stacks.  It provides the ability to
/// listen for packets on a specified port and send replies.
pub trait UdpFullStack: UdpClientStack {
	/// Future returned by `bind` function.
	type BindFuture<'m>: Future<Output = Result<(), Self::Error>> + 'm
	where
		Self: 'm;

	/// Bind a UDP socket with a specified port
	fn bind<'m>(
		&'m mut self,
		socket: &'m mut Self::UdpSocket,
		local_port: u16,
	) -> Self::BindFuture<'m>;

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

	/// Send a packet to a remote host/port.
	fn send_to<'m>(
		&'m mut self,
		socket: &'m mut Self::UdpSocket,
		remote: SocketAddr,
		buffer: &'m [u8],
	) -> Self::SendToFuture<'m>;
}

impl<T: UdpClientStack> UdpClientStack for &mut T {
	type Error = T::Error;
	type UdpSocket = T::UdpSocket;

	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::UdpSocket,
		remote: SocketAddr,
	) -> Self::ConnectFuture<'m> {
		T::connect(self, socket, remote)
	}

	type SendFuture<'m> = T::SendFuture<'m> where Self: 'm;
	fn send<'m>(
		&'m mut self,
		socket: &'m mut Self::UdpSocket,
		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::UdpSocket,
		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::UdpSocket) -> Self::CloseFuture<'m> {
		T::close(self, socket)
	}
}

impl<T: UdpFullStack> UdpFullStack for &mut T {
	type BindFuture<'m> = T::BindFuture<'m> where Self: 'm;
	fn bind<'m>(
		&'m mut self,
		socket: &'m mut Self::UdpSocket,
		local_port: u16,
	) -> Self::BindFuture<'m> {
		T::bind(self, socket, local_port)
	}

	type SendToFuture<'m> = T::SendToFuture<'m> where Self: 'm;
	fn send_to<'m>(
		&'m mut self,
		socket: &'m mut Self::UdpSocket,
		remote: SocketAddr,
		buffer: &'m [u8],
	) -> Self::SendToFuture<'m> {
		T::send_to(self, socket, remote, buffer)
	}
}