diff options
| -rw-r--r-- | embassy-net/src/udp.rs | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 6e50c4e01..1d5360187 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs | |||
| @@ -138,6 +138,35 @@ impl<'a> UdpSocket<'a> { | |||
| 138 | }) | 138 | }) |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | /// Receive a datagram with a zero-copy function. | ||
| 142 | /// | ||
| 143 | /// When no datagram is available, this method will return `Poll::Pending` and | ||
| 144 | /// register the current task to be notified when a datagram is received. | ||
| 145 | /// | ||
| 146 | /// When a datagram is received, this method will call the provided function | ||
| 147 | /// with the number of bytes received and the remote endpoint and return | ||
| 148 | /// `Poll::Ready` with the function's returned value. | ||
| 149 | pub async fn recv_from_with<F, R>(&mut self, f: F) -> R | ||
| 150 | where | ||
| 151 | F: FnOnce(&[u8], UdpMetadata) -> R, | ||
| 152 | { | ||
| 153 | let mut f = Some(f); | ||
| 154 | poll_fn(move |cx| { | ||
| 155 | self.with_mut(|s, _| { | ||
| 156 | match s.recv() { | ||
| 157 | Ok((buffer, endpoint)) => Poll::Ready(unwrap!(f.take())(buffer, endpoint)), | ||
| 158 | Err(udp::RecvError::Truncated) => unreachable!(), | ||
| 159 | Err(udp::RecvError::Exhausted) => { | ||
| 160 | // socket buffer is empty wait until at least one byte has arrived | ||
| 161 | s.register_recv_waker(cx.waker()); | ||
| 162 | Poll::Pending | ||
| 163 | } | ||
| 164 | } | ||
| 165 | }) | ||
| 166 | }) | ||
| 167 | .await | ||
| 168 | } | ||
| 169 | |||
| 141 | /// Send a datagram to the specified remote endpoint. | 170 | /// Send a datagram to the specified remote endpoint. |
| 142 | /// | 171 | /// |
| 143 | /// This method will wait until the datagram has been sent. | 172 | /// This method will wait until the datagram has been sent. |
| @@ -181,6 +210,40 @@ impl<'a> UdpSocket<'a> { | |||
| 181 | }) | 210 | }) |
| 182 | } | 211 | } |
| 183 | 212 | ||
| 213 | /// Send a datagram to the specified remote endpoint with a zero-copy function. | ||
| 214 | /// | ||
| 215 | /// This method will wait until the buffer can fit the requested size before | ||
| 216 | /// calling the function to fill its contents. | ||
| 217 | /// | ||
| 218 | /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` | ||
| 219 | pub async fn send_to_with<T, F, R>(&mut self, size: usize, remote_endpoint: T, f: F) -> Result<R, SendError> | ||
| 220 | where | ||
| 221 | T: Into<UdpMetadata> + Copy, | ||
| 222 | F: FnOnce(&mut [u8]) -> R, | ||
| 223 | { | ||
| 224 | let mut f = Some(f); | ||
| 225 | poll_fn(move |cx| { | ||
| 226 | self.with_mut(|s, _| { | ||
| 227 | match s.send(size, remote_endpoint) { | ||
| 228 | Ok(buffer) => Poll::Ready(Ok(unwrap!(f.take())(buffer))), | ||
| 229 | Err(udp::SendError::BufferFull) => { | ||
| 230 | s.register_send_waker(cx.waker()); | ||
| 231 | Poll::Pending | ||
| 232 | } | ||
| 233 | Err(udp::SendError::Unaddressable) => { | ||
| 234 | // If no sender/outgoing port is specified, there is not really "no route" | ||
| 235 | if s.endpoint().port == 0 { | ||
| 236 | Poll::Ready(Err(SendError::SocketNotBound)) | ||
| 237 | } else { | ||
| 238 | Poll::Ready(Err(SendError::NoRoute)) | ||
| 239 | } | ||
| 240 | } | ||
| 241 | } | ||
| 242 | }) | ||
| 243 | }) | ||
| 244 | .await | ||
| 245 | } | ||
| 246 | |||
| 184 | /// Returns the local endpoint of the socket. | 247 | /// Returns the local endpoint of the socket. |
| 185 | pub fn endpoint(&self) -> IpListenEndpoint { | 248 | pub fn endpoint(&self) -> IpListenEndpoint { |
| 186 | self.with(|s, _| s.endpoint()) | 249 | self.with(|s, _| s.endpoint()) |
