use std::io;
use std::net::{SocketAddr, UdpSocket};
use std::time::Duration;
const DATAGRAM: usize = 8192;
pub trait Transport: Send {
fn send(&self, to: SocketAddr, bytes: &[u8]) -> io::Result<()>;
fn recv(&self, wait: Duration) -> io::Result<Option<(SocketAddr, Vec<u8>)>>;
}
pub struct Udp(UdpSocket);
impl Udp {
pub fn bind(addr: SocketAddr) -> io::Result<Udp> {
UdpSocket::bind(addr).map(Udp)
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.0.local_addr()
}
}
impl Transport for Udp {
fn send(&self, to: SocketAddr, bytes: &[u8]) -> io::Result<()> {
self.0.send_to(bytes, to).map(|_| ())
}
fn recv(&self, wait: Duration) -> io::Result<Option<(SocketAddr, Vec<u8>)>> {
self.0
.set_read_timeout(Some(wait.max(Duration::from_millis(1))))?;
let mut buf = vec![0u8; DATAGRAM];
match self.0.recv_from(&mut buf) {
Ok((n, from)) => {
buf.truncate(n);
Ok(Some((from, buf)))
}
Err(e) => elapsed(&e).then_some(None).ok_or(e),
}
}
}
fn elapsed(e: &io::Error) -> bool {
matches!(
e.kind(),
io::ErrorKind::WouldBlock | io::ErrorKind::TimedOut
)
}
#[cfg(test)]
mod tests;