Touch up codes for UDP

* Move to `std::net` as it's all purely UDP related
* Rename to `UdpCodec` and `UdpFramed` to give a consistent `Udp` prefix
* Add `RecvDgram`, rename `SendDGram` to `SendDgram`
* Touch up some style here and there
This commit is contained in:
Alex Crichton 2016-11-22 11:48:09 -08:00
parent 0d10b0e05a
commit 9b62ade962
6 changed files with 293 additions and 322 deletions

View File

@ -8,21 +8,20 @@ extern crate log;
use std::io;
use std::net::{SocketAddr};
use futures::{future, Future, Stream, Sink};
use tokio_core::io::{CodecUdp};
use tokio_core::net::{UdpSocket};
use tokio_core::net::{UdpSocket, UdpCodec};
use tokio_core::reactor::{Core, Timeout};
use std::time::Duration;
use std::str;
/// This is a basic example of leveraging `FramedUdp` to create
/// a simple UDP client and server which speak a custom Protocol.
/// a simple UDP client and server which speak a custom Protocol.
/// `FramedUdp` applies a `Codec` to the input and output of an
/// `Evented`
/// Simple Newline based parser,
/// Simple Newline based parser,
/// This is for a connectionless server, it must keep track
/// of the Socket address of the last peer to contact it
/// so that it can respond back.
/// so that it can respond back.
/// In the real world, one would probably
/// want an associative of remote peers to their state
///
@ -32,7 +31,7 @@ pub struct LineCodec {
addr : Option<SocketAddr>
}
impl CodecUdp for LineCodec {
impl UdpCodec for LineCodec {
type In = Vec<Vec<u8>>;
type Out = Vec<u8>;
@ -48,12 +47,12 @@ impl CodecUdp for LineCodec {
"failed to find newline in datagram"))
}
}
fn encode(&mut self, item: &Vec<u8>, into: &mut Vec<u8>) -> SocketAddr {
fn encode(&mut self, item: Vec<u8>, into: &mut Vec<u8>) -> SocketAddr {
trace!("encoding {}", str::from_utf8(item.as_slice()).unwrap());
into.extend_from_slice(item.as_slice());
into.push('\n' as u8);
self.addr.unwrap()
}
}
@ -64,7 +63,7 @@ fn main() {
let mut core = Core::new().unwrap();
let handle = core.handle();
//create the line codec parser for each
//create the line codec parser for each
let srvcodec = LineCodec { addr : None };
let clicodec = LineCodec { addr : None };
@ -82,24 +81,24 @@ fn main() {
let (client, _buf) = core.run(job).unwrap();
//We create a FramedUdp instance, which associates a socket
//with a codec. We then immediate split that into the
//with a codec. We then immediate split that into the
//receiving side `Stream` and the writing side `Sink`
let (srvstream, srvsink) = server.framed(srvcodec).split();
let (srvsink, srvstream) = server.framed(srvcodec).split();
//`Stream::fold` runs once per every received datagram.
//Note that we pass srvsink into fold, so that it can be
//supplied to every iteration. The reason for this is
//sink.send moves itself into `send` and then returns itself
let srvloop = srvstream.fold(srvsink, move |sink, lines| {
let srvloop = srvstream.fold(srvsink, move |sink, lines| {
println!("{}", str::from_utf8(lines[0].as_slice()).unwrap());
sink.send(b"PONG".to_vec())
}).map(|_| ());
//We create another FramedUdp instance, this time for the client socket
let (clistream, clisink) = client.framed(clicodec).split();
let (clisink, clistream) = client.framed(clicodec).split();
//And another infinite iteration
let cliloop = clistream.fold(clisink, move |sink, lines| {
let cliloop = clistream.fold(clisink, move |sink, lines| {
println!("{}", str::from_utf8(lines[0].as_slice()).unwrap());
sink.send(b"PING".to_vec())
}).map(|_| ());

View File

@ -33,7 +33,6 @@ macro_rules! try_nb {
mod copy;
mod frame;
mod udp_frame;
mod flush;
mod read_exact;
mod read_to_end;
@ -44,7 +43,6 @@ mod window;
mod write_all;
pub use self::copy::{copy, Copy};
pub use self::frame::{EasyBuf, EasyBufMut, Framed, Codec};
pub use self::udp_frame::{FramedUdp, framed_udp, FramedUdpRead, FramedUdpWrite, CodecUdp, VecDGramCodec};
pub use self::flush::{flush, Flush};
pub use self::read_exact::{read_exact, ReadExact};
pub use self::read_to_end::{read_to_end, ReadToEnd};

View File

@ -1,262 +0,0 @@
use std::io;
use std::net::SocketAddr;
use net::UdpSocket;
use futures::{Async, Poll, Stream, Sink, StartSend, AsyncSink};
use futures::sync::BiLock;
/// Encoding of frames via buffers.
///
/// This trait is used when constructing an instance of `FramedUdp`. It provides
/// one type: `Out` for encoding outgoing frames according to a protocol.
///
/// Because UDP is a connectionless protocol, the encode method will also be
/// responsible for determining the remote host to which the datagram should be
/// sent
///
/// The trait itself is implemented on a type that can track state for decoding
/// or encoding, which is particularly useful for streaming parsers. In many
/// cases, though, this type will simply be a unit struct (e.g. `struct
/// HttpCodec`).
pub trait CodecUdp {
/// The type of frames to be encoded.
type Out;
/// The type of decoded frames.
type In;
/// Encodes a frame into the buffer provided.
///
/// This method will encode `msg` into the byte buffer provided by `buf`.
/// The `buf` provided is an internal buffer of the `Framed` instance and
/// will be written out when possible.
///
/// The encode method also determines the destination to which the buffer should
/// be directed, which will be returned as a SocketAddr;
fn encode(&mut self, msg: &Self::Out, buf: &mut Vec<u8>) -> SocketAddr;
/// Attempts to decode a frame from the provided buffer of bytes.
///
/// This method is called by `FramedUdp` on a single datagram which has been
/// read from a socket.
///
/// It is required that the decode method empty the read buffer in every call to
/// decode, as the next poll_read that occurs will write the next datagram
/// into the buffer, without regard for what is already there.
///
/// Finally, if the bytes in the buffer are malformed then an error is
/// returned indicating why. This informs `Framed` that the stream is now
/// corrupt and should be terminated.
///
fn decode(&mut self, src: &SocketAddr, buf: &[u8]) -> Result<Self::In, io::Error>;
}
/// A unified `Stream` and `Sink` interface to an underlying `Io` object, using
/// the `CodecUdp` trait to encode and decode frames.
///
/// You can acquire a `Framed` instance by using the `Io::framed` adapter.
pub struct FramedUdp<C> {
socket: UdpSocket,
codec: C,
out_addr : Option<SocketAddr>,
rd: Vec<u8>,
wr: Vec<u8>,
}
impl<C : CodecUdp> Stream for FramedUdp<C> {
type Item = C::In;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<C::In>, io::Error> {
loop {
let ret = self.socket.recv_from(self.rd.as_mut_slice());
match ret {
Ok((n, addr)) => {
trace!("read {} bytes", n);
trace!("attempting to decode a frame");
let frame = try!(self.codec.decode(&addr, & self.rd[.. n]));
trace!("frame decoded from buffer");
return Ok(Async::Ready(Some(frame)));
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
return Ok(Async::NotReady)
}
Err(e) => return Err(e),
}
}
}
}
impl<C : CodecUdp> Sink for FramedUdp<C> {
type SinkItem = C::Out;
type SinkError = io::Error;
fn start_send(&mut self, item: C::Out) -> StartSend<C::Out, io::Error> {
if self.wr.len() > 0 {
try!(self.poll_complete());
if self.wr.len() > 0 {
return Ok(AsyncSink::NotReady(item));
}
}
self.out_addr = Some(self.codec.encode(&item, &mut self.wr));
Ok(AsyncSink::Ready)
}
fn poll_complete(&mut self) -> Poll<(), io::Error> {
trace!("flushing framed transport");
if !self.wr.is_empty() {
if let Some(outaddr) = self.out_addr {
let remaining = self.wr.len();
trace!("writing; remaining={}", remaining);
let n = try_nb!(self.socket.send_to(self.wr.as_slice(), &outaddr));
trace!("written {}", n);
self.wr.clear();
self.out_addr = None;
if n != remaining {
return Err(io::Error::new(io::ErrorKind::Other,
"failed to write entire datagram to socket"));
}
}
else {
panic!("outbound stream in invalid state: out_addr is not known");
}
}
return Ok(Async::Ready(()));
}
}
/// Helper function that Creates a new FramedUdp object. It moves the supplied socket, codec
/// into the resulting FramedUdp
pub fn framed_udp<C>(socket : UdpSocket, codec : C) -> FramedUdp<C> {
FramedUdp::new(
socket,
codec,
vec![0; 64 * 1024],
Vec::with_capacity(64 * 1024)
)
}
impl<C> FramedUdp<C> {
/// Creates a new FramedUdp object. It moves the supplied socket, codec
/// supplied vecs.
fn new(sock : UdpSocket, codec : C, rd_buf : Vec<u8>, wr_buf : Vec<u8>) -> FramedUdp<C> {
FramedUdp {
socket: sock,
codec : codec,
out_addr: None,
rd: rd_buf,
wr: wr_buf
}
}
/// Splits this `Stream + Sink` object into separate `Stream` and `Sink`
/// objects, which can be useful when you want to split ownership between
/// tasks, or allow direct interaction between the two objects (e.g. via
/// `Sink::send_all`).
pub fn split(self) -> (FramedUdpRead<C>, FramedUdpWrite<C>) {
let (a, b) = BiLock::new(self);
let read = FramedUdpRead { framed: a };
let write = FramedUdpWrite { framed: b };
(read, write)
}
/// Returns a reference to the underlying I/O stream wrapped by `Framed`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn get_ref(&self) -> &UdpSocket {
&self.socket
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `Framed`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn get_mut(&mut self) -> &mut UdpSocket {
&mut self.socket
}
/// Consumes the `Framed`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn into_inner(self) -> UdpSocket {
self.socket
}
}
/// A `Stream` interface to an underlying `Io` object, using the `CodecUdp` trait
/// to decode frames.
pub struct FramedUdpRead<C> {
framed: BiLock<FramedUdp<C>>,
}
impl<C : CodecUdp> Stream for FramedUdpRead<C> {
type Item = C::In;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<C::In>, io::Error> {
if let Async::Ready(mut guard) = self.framed.poll_lock() {
guard.poll()
} else {
Ok(Async::NotReady)
}
}
}
/// A `Sink` interface to an underlying `Io` object, using the `CodecUdp` trait
/// to encode frames.
pub struct FramedUdpWrite<C> {
framed: BiLock<FramedUdp<C>>,
}
impl<C : CodecUdp> Sink for FramedUdpWrite<C> {
type SinkItem = C::Out;
type SinkError = io::Error;
fn start_send(&mut self, item: C::Out) -> StartSend<C::Out, io::Error> {
if let Async::Ready(mut guard) = self.framed.poll_lock() {
guard.start_send(item)
} else {
Ok(AsyncSink::NotReady(item))
}
}
fn poll_complete(&mut self) -> Poll<(), io::Error> {
if let Async::Ready(mut guard) = self.framed.poll_lock() {
guard.poll_complete()
} else {
Ok(Async::NotReady)
}
}
}
/// Default implementation of a DGram "parser"
/// This receives and produces a tuple of ('SocketAddr', `Vec`<u8>)
pub struct VecDGramCodec;
impl CodecUdp for VecDGramCodec {
type In = (SocketAddr, Vec<u8>);
type Out = (SocketAddr, Vec<u8>);
fn decode(&mut self, addr : &SocketAddr, buf: &[u8]) -> Result<Self::In, io::Error> {
Ok((*addr, buf.into()))
}
fn encode(&mut self, item: &Self::Out, into: &mut Vec<u8>) -> SocketAddr {
into.extend_from_slice(item.1.as_slice());
into.push('\n' as u8);
item.0
}
}

View File

@ -8,4 +8,4 @@ mod udp;
pub use self::tcp::{TcpStream, TcpStreamNew};
pub use self::tcp::{TcpListener, Incoming};
pub use self::udp::UdpSocket;
pub use self::udp::{UdpSocket, UdpCodec, UdpFramed};

154
src/net/udp/frame.rs Normal file
View File

@ -0,0 +1,154 @@
use std::io;
use std::net::{SocketAddr, Ipv4Addr, SocketAddrV4};
use futures::{Async, Poll, Stream, Sink, StartSend, AsyncSink};
use net::UdpSocket;
/// Encoding of frames via buffers.
///
/// This trait is used when constructing an instance of `UdpFramed` and provides
/// the `In` and `Out` types which are decoded and encoded from the socket,
/// respectively.
///
/// Because UDP is a connectionless protocol, the `decode` method receives the
/// address where data came from and the `encode` method is also responsible for
/// determining the remote host to which the datagram should be sent
///
/// The trait itself is implemented on a type that can track state for decoding
/// or encoding, which is particularly useful for streaming parsers. In many
/// cases, though, this type will simply be a unit struct (e.g. `struct
/// HttpCodec`).
pub trait UdpCodec {
/// The type of decoded frames.
type In;
/// The type of frames to be encoded.
type Out;
/// Attempts to decode a frame from the provided buffer of bytes.
///
/// This method is called by `UdpFramed` on a single datagram which has been
/// read from a socket. The `buf` argument contains the data that was
/// received from the remote address, and `src` is the address the data came
/// from. Note that typically this method should require the entire contents
/// of `buf` to be valid or otherwise return an error with trailing data.
///
/// Finally, if the bytes in the buffer are malformed then an error is
/// returned indicating why. This informs `Framed` that the stream is now
/// corrupt and should be terminated.
fn decode(&mut self, src: &SocketAddr, buf: &[u8]) -> io::Result<Self::In>;
/// Encodes a frame into the buffer provided.
///
/// This method will encode `msg` into the byte buffer provided by `buf`.
/// The `buf` provided is an internal buffer of the `Framed` instance and
/// will be written out when possible.
///
/// The encode method also determines the destination to which the buffer
/// should be directed, which will be returned as a `SocketAddr`.
fn encode(&mut self, msg: Self::Out, buf: &mut Vec<u8>) -> SocketAddr;
}
/// A unified `Stream` and `Sink` interface to an underlying `UdpSocket`, using
/// the `UdpCodec` trait to encode and decode frames.
///
/// You can acquire a `UdpFramed` instance by using the `UdpSocket::framed`
/// adapter.
pub struct UdpFramed<C> {
socket: UdpSocket,
codec: C,
rd: Vec<u8>,
wr: Vec<u8>,
out_addr: SocketAddr,
}
impl<C: UdpCodec> Stream for UdpFramed<C> {
type Item = C::In;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<C::In>, io::Error> {
let (n, addr) = try_nb!(self.socket.recv_from(&mut self.rd));
trace!("received {} bytes, decoding", n);
let frame = try!(self.codec.decode(&addr, &self.rd[..n]));
trace!("frame decoded from buffer");
Ok(Async::Ready(Some(frame)))
}
}
impl<C: UdpCodec> Sink for UdpFramed<C> {
type SinkItem = C::Out;
type SinkError = io::Error;
fn start_send(&mut self, item: C::Out) -> StartSend<C::Out, io::Error> {
if self.wr.len() > 0 {
try!(self.poll_complete());
if self.wr.len() > 0 {
return Ok(AsyncSink::NotReady(item));
}
}
self.out_addr = self.codec.encode(item, &mut self.wr);
Ok(AsyncSink::Ready)
}
fn poll_complete(&mut self) -> Poll<(), io::Error> {
trace!("flushing framed transport");
if self.wr.is_empty() {
return Ok(Async::Ready(()))
}
trace!("writing; remaining={}", self.wr.len());
let n = try_nb!(self.socket.send_to(&self.wr, &self.out_addr));
trace!("written {}", n);
let wrote_all = n == self.wr.len();
self.wr.clear();
if wrote_all {
Ok(Async::Ready(()))
} else {
Err(io::Error::new(io::ErrorKind::Other,
"failed to write entire datagram to socket"))
}
}
}
pub fn new<C: UdpCodec>(socket: UdpSocket, codec: C) -> UdpFramed<C> {
UdpFramed {
socket: socket,
codec: codec,
out_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)),
rd: vec![0; 64 * 1024],
wr: Vec::with_capacity(8 * 1024),
}
}
impl<C> UdpFramed<C> {
/// Returns a reference to the underlying I/O stream wrapped by `Framed`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn get_ref(&self) -> &UdpSocket {
&self.socket
}
/// Returns a mutable reference to the underlying I/O stream wrapped by
/// `Framed`.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn get_mut(&mut self) -> &mut UdpSocket {
&mut self.socket
}
/// Consumes the `Framed`, returning its underlying I/O stream.
///
/// Note that care should be taken to not tamper with the underlying stream
/// of data coming in as it may corrupt the stream of frames otherwise being
/// worked with.
pub fn into_inner(self) -> UdpSocket {
self.socket
}
}

View File

@ -1,10 +1,10 @@
use std::io;
use std::mem;
use std::net::{self, SocketAddr, Ipv4Addr, Ipv6Addr};
use std::fmt;
use io::{FramedUdp, framed_udp};
use futures::{Async, Future, Poll};
use mio;
use std::mem;
use reactor::{Handle, PollEvented};
@ -13,6 +13,9 @@ pub struct UdpSocket {
io: PollEvented<mio::udp::UdpSocket>,
}
mod frame;
pub use self::frame::{UdpFramed, UdpCodec};
impl UdpSocket {
/// Create a new UDP socket bound to the specified address.
///
@ -43,11 +46,27 @@ impl UdpSocket {
UdpSocket::new(udp, handle)
}
/// Creates a FramedUdp object, which leverages a supplied `EncodeUdp`
/// and `DecodeUdp` to implement `Stream` and `Sink`
/// This moves the socket into the newly created FramedUdp object
pub fn framed<C>(self, codec : C) -> FramedUdp<C> {
framed_udp(self, codec)
/// Provides a `Stream` and `Sink` interface for reading and writing to this
/// `UdpSocket` object, using the provided `UdpCodec` to read and write the
/// raw data.
///
/// Raw UDP sockets work with datagrams, but higher-level code usually
/// wants to batch these into meaningful chunks, called "frames". This
/// method layers framing on top of this socket by using the `UdpCodec`
/// trait to handle encoding and decoding of messages frames. Note that
/// the incoming and outgoing frame types may be distinct.
///
/// This function returns a *single* object that is both `Stream` and
/// `Sink`; grouping this into a single object is often useful for layering
/// things which require both read and write access to the underlying
/// object.
///
/// If you want to work more directly with the streams and sink, consider
/// calling `split` on the `UdpFramed` returned by this method, which will
/// break them into separate objects, allowing them to interact more
/// easily.
pub fn framed<C: UdpCodec>(self, codec: C) -> UdpFramed<C> {
frame::new(self, codec)
}
/// Returns the local address that this stream is bound to.
@ -93,27 +112,27 @@ impl UdpSocket {
Err(e) => Err(e),
}
}
/// Creates a future that will write the entire contents of the buffer `buf` to
/// the stream `a` provided.
/// Creates a future that will write the entire contents of the buffer
/// `buf` provided as a datagram to this socket.
///
/// The returned future will return after data has been written to the outbound
/// socket.
/// The future will resolve to the stream as well as the buffer (for reuse if
/// needed).
/// The returned future will return after data has been written to the
/// outbound socket. The future will resolve to the stream as well as the
/// buffer (for reuse if needed).
///
/// Any error which happens during writing will cause both the stream and the
/// buffer to get destroyed.
/// Any error which happens during writing will cause both the stream and
/// the buffer to get destroyed. Note that failure to write the entire
/// buffer is considered an error for the purposes of sending a datagram.
///
/// The `buf` parameter here only requires the `AsRef<[u8]>` trait, which should
/// be broadly applicable to accepting data which can be converted to a slice.
/// The `Window` struct is also available in this crate to provide a different
/// window into a slice if necessary.
pub fn send_dgram<T>(self, buf: T, addr : SocketAddr) -> SendDGram<T>
/// The `buf` parameter here only requires the `AsRef<[u8]>` trait, which
/// should be broadly applicable to accepting data which can be converted
/// to a slice. The `Window` struct is also available in this crate to
/// provide a different window into a slice if necessary.
pub fn send_dgram<T>(self, buf: T, addr: SocketAddr) -> SendDgram<T>
where T: AsRef<[u8]>,
{
SendDGram {
state: UdpState::Writing {
SendDgram {
state: SendState::Writing {
sock: self,
addr: addr,
buf: buf,
@ -137,6 +156,31 @@ impl UdpSocket {
}
}
/// Creates a future that receive a datagram to be written to the buffer
/// provided.
///
/// The returned future will return after a datagram has been received on
/// this socket. The future will resolve to the socket, the buffer, the
/// amount of data read, and the address the data was received from.
///
/// An error during reading will cause the socket and buffer to get
/// destroyed and the socket will be returned.
///
/// The `buf` parameter here only requires the `AsMut<[u8]>` trait, which
/// should be broadly applicable to accepting data which can be converted
/// to a slice. The `Window` struct is also available in this crate to
/// provide a different window into a slice if necessary.
pub fn recv_dgram<T>(self, buf: T) -> RecvDgram<T>
where T: AsMut<[u8]>,
{
RecvDgram {
state: RecvState::Reading {
sock: self,
buf: buf,
},
}
}
/// Gets the value of the `SO_BROADCAST` option for this socket.
///
/// For more information about this option, see
@ -284,16 +328,14 @@ impl fmt::Debug for UdpSocket {
}
}
/// A future used to write the entire contents of some data to a stream.
/// A future used to write the entire contents of some data to a UDP socket.
///
/// This is created by the [`write_all`] top-level method.
///
/// [`write_all`]: fn.write_all.html
pub struct SendDGram<T> {
state: UdpState<T>,
/// This is created by the `UdpSocket::send_dgram` method.
pub struct SendDgram<T> {
state: SendState<T>,
}
enum UdpState<T> {
enum SendState<T> {
Writing {
sock: UdpSocket,
buf: T,
@ -302,11 +344,11 @@ enum UdpState<T> {
Empty,
}
fn incomplete_write(reason : &str) -> io::Error {
fn incomplete_write(reason: &str) -> io::Error {
io::Error::new(io::ErrorKind::Other, reason)
}
impl<T> Future for SendDGram<T>
impl<T> Future for SendDgram<T>
where T: AsRef<[u8]>,
{
type Item = (UdpSocket, T);
@ -314,19 +356,59 @@ impl<T> Future for SendDGram<T>
fn poll(&mut self) -> Poll<(UdpSocket, T), io::Error> {
match self.state {
UdpState::Writing { ref sock, ref buf, ref addr} => {
let buf = buf.as_ref();
let n = try_nb!(sock.send_to(&buf, addr));
if n != buf.len() {
return Err(incomplete_write("Failed to send entire message in datagram"))
SendState::Writing { ref sock, ref buf, ref addr } => {
let n = try_nb!(sock.send_to(buf.as_ref(), addr));
if n != buf.as_ref().len() {
return Err(incomplete_write("failed to send entire message \
in datagram"))
}
}
UdpState::Empty => panic!("poll a SendDGram after it's done"),
SendState::Empty => panic!("poll a SendDgram after it's done"),
}
match mem::replace(&mut self.state, UdpState::Empty) {
UdpState::Writing { sock, buf, .. } => Ok(Async::Ready((sock, (buf).into()))),
UdpState::Empty => panic!(),
match mem::replace(&mut self.state, SendState::Empty) {
SendState::Writing { sock, buf, addr: _ } => {
Ok(Async::Ready((sock, buf)))
}
SendState::Empty => panic!(),
}
}
}
/// A future used to receive a datagram from a UDP socket.
///
/// This is created by the `UdpSocket::recv_dgram` method.
pub struct RecvDgram<T> {
state: RecvState<T>,
}
enum RecvState<T> {
Reading {
sock: UdpSocket,
buf: T,
},
Empty,
}
impl<T> Future for RecvDgram<T>
where T: AsMut<[u8]>,
{
type Item = (UdpSocket, T, usize, SocketAddr);
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, io::Error> {
let (n, addr) = match self.state {
RecvState::Reading { ref sock, ref mut buf } => {
try_nb!(sock.recv_from(buf.as_mut()))
}
RecvState::Empty => panic!("poll a RecvDgram after it's done"),
};
match mem::replace(&mut self.state, RecvState::Empty) {
RecvState::Reading { sock, buf } => {
Ok(Async::Ready((sock, buf, n, addr)))
}
RecvState::Empty => panic!(),
}
}
}