mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-29 00:00:11 +02:00
util: resurrect UdpFramed (#3044)
This commit is contained in:
@@ -24,8 +24,9 @@ categories = ["asynchronous"]
|
|||||||
default = []
|
default = []
|
||||||
|
|
||||||
# Shorthand for enabling everything
|
# Shorthand for enabling everything
|
||||||
full = ["codec", "compat", "io", "time"]
|
full = ["codec", "compat", "io", "time", "net"]
|
||||||
|
|
||||||
|
net = ["tokio/net"]
|
||||||
compat = ["futures-io",]
|
compat = ["futures-io",]
|
||||||
codec = ["tokio/stream"]
|
codec = ["tokio/stream"]
|
||||||
time = ["tokio/time","slab"]
|
time = ["tokio/time","slab"]
|
||||||
|
|||||||
@@ -18,17 +18,15 @@ macro_rules! cfg_compat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
macro_rules! cfg_net {
|
||||||
macro_rules! cfg_udp {
|
|
||||||
($($item:item)*) => {
|
($($item:item)*) => {
|
||||||
$(
|
$(
|
||||||
#[cfg(all(feature = "udp", feature = "codec"))]
|
#[cfg(all(feature = "net", feature = "codec"))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(all(feature = "udp", feature = "codec"))))]
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "net", feature = "codec"))))]
|
||||||
$item
|
$item
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
macro_rules! cfg_io {
|
macro_rules! cfg_io {
|
||||||
($($item:item)*) => {
|
($($item:item)*) => {
|
||||||
|
|||||||
@@ -30,14 +30,9 @@ cfg_codec! {
|
|||||||
pub mod codec;
|
pub mod codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
cfg_net! {
|
||||||
Disabled due to removal of poll_ functions on UdpSocket.
|
|
||||||
|
|
||||||
See https://github.com/tokio-rs/tokio/issues/2830
|
|
||||||
cfg_udp! {
|
|
||||||
pub mod udp;
|
pub mod udp;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
cfg_compat! {
|
cfg_compat! {
|
||||||
pub mod compat;
|
pub mod compat;
|
||||||
|
|||||||
+48
-16
@@ -1,17 +1,16 @@
|
|||||||
use crate::codec::{Decoder, Encoder};
|
use crate::codec::{Decoder, Encoder};
|
||||||
|
|
||||||
use tokio::{net::UdpSocket, stream::Stream};
|
use tokio::{io::ReadBuf, net::UdpSocket, stream::Stream};
|
||||||
|
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use futures_core::ready;
|
use futures_core::ready;
|
||||||
use futures_sink::Sink;
|
use futures_sink::Sink;
|
||||||
use std::io;
|
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
use std::{io, mem::MaybeUninit};
|
||||||
|
|
||||||
/// A unified `Stream` and `Sink` interface to an underlying `UdpSocket`, using
|
/// A unified [`Stream`] and [`Sink`] interface to an underlying `UdpSocket`, using
|
||||||
/// the `Encoder` and `Decoder` traits to encode and decode frames.
|
/// the `Encoder` and `Decoder` traits to encode and decode frames.
|
||||||
///
|
///
|
||||||
/// Raw UDP sockets work with datagrams, but higher-level code usually wants to
|
/// Raw UDP sockets work with datagrams, but higher-level code usually wants to
|
||||||
@@ -20,13 +19,17 @@ use std::task::{Context, Poll};
|
|||||||
/// handle encoding and decoding of messages frames. Note that the incoming and
|
/// handle encoding and decoding of messages frames. Note that the incoming and
|
||||||
/// outgoing frame types may be distinct.
|
/// outgoing frame types may be distinct.
|
||||||
///
|
///
|
||||||
/// This function returns a *single* object that is both `Stream` and `Sink`;
|
/// 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
|
/// grouping this into a single object is often useful for layering things which
|
||||||
/// require both read and write access to the underlying object.
|
/// require both read and write access to the underlying object.
|
||||||
///
|
///
|
||||||
/// If you want to work more directly with the streams and sink, consider
|
/// 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
|
/// calling [`split`] on the `UdpFramed` returned by this method, which will break
|
||||||
/// them into separate objects, allowing them to interact more easily.
|
/// them into separate objects, allowing them to interact more easily.
|
||||||
|
///
|
||||||
|
/// [`Stream`]: tokio::stream::Stream
|
||||||
|
/// [`Sink`]: futures_sink::Sink
|
||||||
|
/// [`split`]: https://docs.rs/futures/0.3/futures/stream/trait.StreamExt.html#method.split
|
||||||
#[must_use = "sinks do nothing unless polled"]
|
#[must_use = "sinks do nothing unless polled"]
|
||||||
#[cfg_attr(docsrs, doc(all(feature = "codec", feature = "udp")))]
|
#[cfg_attr(docsrs, doc(all(feature = "codec", feature = "udp")))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -41,6 +44,9 @@ pub struct UdpFramed<C> {
|
|||||||
current_addr: Option<SocketAddr>,
|
current_addr: Option<SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const INITIAL_RD_CAPACITY: usize = 64 * 1024;
|
||||||
|
const INITIAL_WR_CAPACITY: usize = 8 * 1024;
|
||||||
|
|
||||||
impl<C: Decoder + Unpin> Stream for UdpFramed<C> {
|
impl<C: Decoder + Unpin> Stream for UdpFramed<C> {
|
||||||
type Item = Result<(C::Item, SocketAddr), C::Error>;
|
type Item = Result<(C::Item, SocketAddr), C::Error>;
|
||||||
|
|
||||||
@@ -69,13 +75,14 @@ impl<C: Decoder + Unpin> Stream for UdpFramed<C> {
|
|||||||
let addr = unsafe {
|
let addr = unsafe {
|
||||||
// Convert `&mut [MaybeUnit<u8>]` to `&mut [u8]` because we will be
|
// Convert `&mut [MaybeUnit<u8>]` to `&mut [u8]` because we will be
|
||||||
// writing to it via `poll_recv_from` and therefore initializing the memory.
|
// writing to it via `poll_recv_from` and therefore initializing the memory.
|
||||||
let buf: &mut [u8] =
|
let buf = &mut *(pin.rd.bytes_mut() as *mut _ as *mut [MaybeUninit<u8>]);
|
||||||
&mut *(pin.rd.bytes_mut() as *mut [MaybeUninit<u8>] as *mut [u8]);
|
let mut read = ReadBuf::uninit(buf);
|
||||||
|
let ptr = read.filled().as_ptr();
|
||||||
|
let res = ready!(Pin::new(&mut pin.socket).poll_recv_from(cx, &mut read));
|
||||||
|
|
||||||
let res = ready!(Pin::new(&mut pin.socket).poll_recv_from(cx, buf));
|
assert_eq!(ptr, read.filled().as_ptr());
|
||||||
|
let addr = res?;
|
||||||
let (n, addr) = res?;
|
pin.rd.advance_mut(read.filled().len());
|
||||||
pin.rd.advance_mut(n);
|
|
||||||
addr
|
addr
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,15 +155,12 @@ impl<I, C: Encoder<I> + Unpin> Sink<(I, SocketAddr)> for UdpFramed<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const INITIAL_RD_CAPACITY: usize = 64 * 1024;
|
|
||||||
const INITIAL_WR_CAPACITY: usize = 8 * 1024;
|
|
||||||
|
|
||||||
impl<C> UdpFramed<C> {
|
impl<C> UdpFramed<C> {
|
||||||
/// Create a new `UdpFramed` backed by the given socket and codec.
|
/// Create a new `UdpFramed` backed by the given socket and codec.
|
||||||
///
|
///
|
||||||
/// See struct level documentation for more details.
|
/// See struct level documentation for more details.
|
||||||
pub fn new(socket: UdpSocket, codec: C) -> UdpFramed<C> {
|
pub fn new(socket: UdpSocket, codec: C) -> UdpFramed<C> {
|
||||||
UdpFramed {
|
Self {
|
||||||
socket,
|
socket,
|
||||||
codec,
|
codec,
|
||||||
out_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)),
|
out_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0)),
|
||||||
@@ -195,4 +199,32 @@ impl<C> UdpFramed<C> {
|
|||||||
pub fn into_inner(self) -> UdpSocket {
|
pub fn into_inner(self) -> UdpSocket {
|
||||||
self.socket
|
self.socket
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the underlying codec wrapped by
|
||||||
|
/// `Framed`.
|
||||||
|
///
|
||||||
|
/// Note that care should be taken to not tamper with the underlying codec
|
||||||
|
/// as it may corrupt the stream of frames otherwise being worked with.
|
||||||
|
pub fn codec(&self) -> &C {
|
||||||
|
&self.codec
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the underlying codec wrapped by
|
||||||
|
/// `UdpFramed`.
|
||||||
|
///
|
||||||
|
/// Note that care should be taken to not tamper with the underlying codec
|
||||||
|
/// as it may corrupt the stream of frames otherwise being worked with.
|
||||||
|
pub fn codec_mut(&mut self) -> &mut C {
|
||||||
|
&mut self.codec
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the read buffer.
|
||||||
|
pub fn read_buffer(&self) -> &BytesMut {
|
||||||
|
&self.rd
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the read buffer.
|
||||||
|
pub fn read_buffer_mut(&mut self) -> &mut BytesMut {
|
||||||
|
&mut self.rd
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! UDP framing
|
//! UDP framing
|
||||||
|
|
||||||
mod frame;
|
mod frame;
|
||||||
pub use self::frame::UdpFramed;
|
pub use frame::UdpFramed;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/*
|
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
use tokio::{net::UdpSocket, stream::StreamExt};
|
use tokio::{net::UdpSocket, stream::StreamExt};
|
||||||
@@ -101,4 +100,3 @@ async fn send_framed_lines_codec() -> std::io::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
Reference in New Issue
Block a user