From 964afb2ce30045caece2c143cd105b7a2c221b8e Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Wed, 26 Sep 2018 15:28:57 -0700 Subject: [PATCH] split facade modules into separate files (#665) --- src/{ => codec}/length_delimited.rs | 362 ++++++++++++++++++- src/codec/mod.rs | 26 ++ src/io.rs | 93 +++++ src/lib.rs | 542 +--------------------------- src/prelude.rs | 54 +++ 5 files changed, 537 insertions(+), 540 deletions(-) rename src/{ => codec}/length_delimited.rs (58%) create mode 100644 src/codec/mod.rs create mode 100644 src/io.rs create mode 100644 src/prelude.rs diff --git a/src/length_delimited.rs b/src/codec/length_delimited.rs similarity index 58% rename from src/length_delimited.rs rename to src/codec/length_delimited.rs index 270a3c1f9..54ec202bb 100644 --- a/src/length_delimited.rs +++ b/src/codec/length_delimited.rs @@ -1,6 +1,364 @@ +//! Frame a stream of bytes based on a length prefix +//! +//! Many protocols delimit their frames by prefacing frame data with a +//! frame head that specifies the length of the frame. The +//! `length_delimited` module provides utilities for handling the length +//! based framing. This allows the consumer to work with entire frames +//! without having to worry about buffering or other framing logic. +//! +//! # Getting started +//! +//! If implementing a protocol from scratch, using length delimited framing +//! is an easy way to get started. [`Codec::new()`] will return a length +//! delimited codec using default configuration values. This can then be +//! used to construct a framer to adapt a full-duplex byte stream into a +//! stream of frames. +//! +//! ``` +//! # extern crate tokio; +//! use tokio::io::{AsyncRead, AsyncWrite}; +//! use tokio::codec::*; +//! +//! fn bind_transport(io: T) +//! -> Framed +//! { +//! Framed::new(io, LengthDelimitedCodec::new()) +//! } +//! # pub fn main() {} +//! ``` +//! +//! The returned transport implements `Sink + Stream` for `BytesMut`. It +//! encodes the frame with a big-endian `u32` header denoting the frame +//! payload length: +//! +//! ```text +//! +----------+--------------------------------+ +//! | len: u32 | frame payload | +//! +----------+--------------------------------+ +//! ``` +//! +//! Specifically, given the following: +//! +//! ``` +//! # extern crate tokio; +//! # extern crate bytes; +//! # extern crate futures; +//! # +//! use tokio::io::{AsyncRead, AsyncWrite}; +//! use tokio::codec::*; +//! use bytes::Bytes; +//! use futures::{Sink, Future}; +//! +//! fn write_frame(io: T) { +//! let mut transport = Framed::new(io, LengthDelimitedCodec::new()); +//! let frame = Bytes::from("hello world"); +//! +//! transport.send(frame).wait().unwrap(); +//! } +//! # +//! # pub fn main() {} +//! ``` +//! +//! The encoded frame will look like this: +//! +//! ```text +//! +---- len: u32 ----+---- data ----+ +//! | \x00\x00\x00\x0b | hello world | +//! +------------------+--------------+ +//! ``` +//! +//! # Decoding +//! +//! [`FramedRead`] adapts an [`AsyncRead`] into a `Stream` of [`BytesMut`], +//! such that each yielded [`BytesMut`] value contains the contents of an +//! entire frame. There are many configuration parameters enabling +//! [`FramedRead`] to handle a wide range of protocols. Here are some +//! examples that will cover the various options at a high level. +//! +//! ## Example 1 +//! +//! The following will parse a `u16` length field at offset 0, including the +//! frame head in the yielded `BytesMut`. +//! +//! ``` +//! # extern crate tokio; +//! # use tokio::io::AsyncRead; +//! # use tokio::codec::length_delimited; +//! # fn bind_read(io: T) { +//! length_delimited::Builder::new() +//! .length_field_offset(0) // default value +//! .length_field_length(2) +//! .length_adjustment(0) // default value +//! .num_skip(0) // Do not strip frame header +//! .new_read(io); +//! # } +//! # pub fn main() {} +//! ``` +//! +//! The following frame will be decoded as such: +//! +//! ```text +//! INPUT DECODED +//! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+ +//! | \x00\x0B | Hello world | --> | \x00\x0B | Hello world | +//! +----------+---------------+ +----------+---------------+ +//! ``` +//! +//! The value of the length field is 11 (`\x0B`) which represents the length +//! of the payload, `hello world`. By default, [`FramedRead`] assumes that +//! the length field represents the number of bytes that **follows** the +//! length field. Thus, the entire frame has a length of 13: 2 bytes for the +//! frame head + 11 bytes for the payload. +//! +//! ## Example 2 +//! +//! The following will parse a `u16` length field at offset 0, omitting the +//! frame head in the yielded `BytesMut`. +//! +//! ``` +//! # extern crate tokio; +//! # use tokio::io::AsyncRead; +//! # use tokio::codec::length_delimited; +//! # fn bind_read(io: T) { +//! length_delimited::Builder::new() +//! .length_field_offset(0) // default value +//! .length_field_length(2) +//! .length_adjustment(0) // default value +//! // `num_skip` is not needed, the default is to skip +//! .new_read(io); +//! # } +//! # pub fn main() {} +//! ``` +//! +//! The following frame will be decoded as such: +//! +//! ```text +//! INPUT DECODED +//! +-- len ---+--- Payload ---+ +--- Payload ---+ +//! | \x00\x0B | Hello world | --> | Hello world | +//! +----------+---------------+ +---------------+ +//! ``` +//! +//! This is similar to the first example, the only difference is that the +//! frame head is **not** included in the yielded `BytesMut` value. +//! +//! ## Example 3 +//! +//! The following will parse a `u16` length field at offset 0, including the +//! frame head in the yielded `BytesMut`. In this case, the length field +//! **includes** the frame head length. +//! +//! ``` +//! # extern crate tokio; +//! # use tokio::io::AsyncRead; +//! # use tokio::codec::length_delimited; +//! # fn bind_read(io: T) { +//! length_delimited::Builder::new() +//! .length_field_offset(0) // default value +//! .length_field_length(2) +//! .length_adjustment(-2) // size of head +//! .num_skip(0) +//! .new_read(io); +//! # } +//! # pub fn main() {} +//! ``` +//! +//! The following frame will be decoded as such: +//! +//! ```text +//! INPUT DECODED +//! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+ +//! | \x00\x0D | Hello world | --> | \x00\x0D | Hello world | +//! +----------+---------------+ +----------+---------------+ +//! ``` +//! +//! In most cases, the length field represents the length of the payload +//! only, as shown in the previous examples. However, in some protocols the +//! length field represents the length of the whole frame, including the +//! head. In such cases, we specify a negative `length_adjustment` to adjust +//! the value provided in the frame head to represent the payload length. +//! +//! ## Example 4 +//! +//! The following will parse a 3 byte length field at offset 0 in a 5 byte +//! frame head, including the frame head in the yielded `BytesMut`. +//! +//! ``` +//! # extern crate tokio; +//! # use tokio::io::AsyncRead; +//! # use tokio::codec::length_delimited; +//! # fn bind_read(io: T) { +//! length_delimited::Builder::new() +//! .length_field_offset(0) // default value +//! .length_field_length(3) +//! .length_adjustment(2) // remaining head +//! .num_skip(0) +//! .new_read(io); +//! # } +//! # pub fn main() {} +//! ``` +//! +//! The following frame will be decoded as such: +//! +//! ```text +//! INPUT +//! +---- len -----+- head -+--- Payload ---+ +//! | \x00\x00\x0B | \xCAFE | Hello world | +//! +--------------+--------+---------------+ +//! +//! DECODED +//! +---- len -----+- head -+--- Payload ---+ +//! | \x00\x00\x0B | \xCAFE | Hello world | +//! +--------------+--------+---------------+ +//! ``` +//! +//! A more advanced example that shows a case where there is extra frame +//! head data between the length field and the payload. In such cases, it is +//! usually desirable to include the frame head as part of the yielded +//! `BytesMut`. This lets consumers of the length delimited framer to +//! process the frame head as needed. +//! +//! The positive `length_adjustment` value lets `FramedRead` factor in the +//! additional head into the frame length calculation. +//! +//! ## Example 5 +//! +//! The following will parse a `u16` length field at offset 1 of a 4 byte +//! frame head. The first byte and the length field will be omitted from the +//! yielded `BytesMut`, but the trailing 2 bytes of the frame head will be +//! included. +//! +//! ``` +//! # extern crate tokio; +//! # use tokio::io::AsyncRead; +//! # use tokio::codec::length_delimited; +//! # fn bind_read(io: T) { +//! length_delimited::Builder::new() +//! .length_field_offset(1) // length of hdr1 +//! .length_field_length(2) +//! .length_adjustment(1) // length of hdr2 +//! .num_skip(3) // length of hdr1 + LEN +//! .new_read(io); +//! # } +//! # pub fn main() {} +//! ``` +//! +//! The following frame will be decoded as such: +//! +//! ```text +//! INPUT +//! +- hdr1 -+-- len ---+- hdr2 -+--- Payload ---+ +//! | \xCA | \x00\x0B | \xFE | Hello world | +//! +--------+----------+--------+---------------+ +//! +//! DECODED +//! +- hdr2 -+--- Payload ---+ +//! | \xFE | Hello world | +//! +--------+---------------+ +//! ``` +//! +//! The length field is situated in the middle of the frame head. In this +//! case, the first byte in the frame head could be a version or some other +//! identifier that is not needed for processing. On the other hand, the +//! second half of the head is needed. +//! +//! `length_field_offset` indicates how many bytes to skip before starting +//! to read the length field. `length_adjustment` is the number of bytes to +//! skip starting at the end of the length field. In this case, it is the +//! second half of the head. +//! +//! ## Example 6 +//! +//! The following will parse a `u16` length field at offset 1 of a 4 byte +//! frame head. The first byte and the length field will be omitted from the +//! yielded `BytesMut`, but the trailing 2 bytes of the frame head will be +//! included. In this case, the length field **includes** the frame head +//! length. +//! +//! ``` +//! # extern crate tokio; +//! # use tokio::io::AsyncRead; +//! # use tokio::codec::length_delimited; +//! # fn bind_read(io: T) { +//! length_delimited::Builder::new() +//! .length_field_offset(1) // length of hdr1 +//! .length_field_length(2) +//! .length_adjustment(-3) // length of hdr1 + LEN, negative +//! .num_skip(3) +//! .new_read(io); +//! # } +//! # pub fn main() {} +//! ``` +//! +//! The following frame will be decoded as such: +//! +//! ```text +//! INPUT +//! +- hdr1 -+-- len ---+- hdr2 -+--- Payload ---+ +//! | \xCA | \x00\x0F | \xFE | Hello world | +//! +--------+----------+--------+---------------+ +//! +//! DECODED +//! +- hdr2 -+--- Payload ---+ +//! | \xFE | Hello world | +//! +--------+---------------+ +//! ``` +//! +//! Similar to the example above, the difference is that the length field +//! represents the length of the entire frame instead of just the payload. +//! The length of `hdr1` and `len` must be counted in `length_adjustment`. +//! Note that the length of `hdr2` does **not** need to be explicitly set +//! anywhere because it already is factored into the total frame length that +//! is read from the byte stream. +//! +//! # Encoding +//! +//! [`FramedWrite`] adapts an [`AsyncWrite`] into a `Sink` of [`BytesMut`], +//! such that each submitted [`BytesMut`] is prefaced by a length field. +//! There are fewer configuration options than [`FramedRead`]. Given +//! protocols that have more complex frame heads, an encoder should probably +//! be written by hand using [`Encoder`]. +//! +//! Here is a simple example, given a `FramedWrite` with the following +//! configuration: +//! +//! ``` +//! # extern crate tokio; +//! # extern crate bytes; +//! # use tokio::io::AsyncWrite; +//! # use tokio::codec::length_delimited; +//! # use bytes::BytesMut; +//! # fn write_frame(io: T) { +//! # let _ = +//! length_delimited::Builder::new() +//! .length_field_length(2) +//! .new_write(io); +//! # } +//! # pub fn main() {} +//! ``` +//! +//! A payload of `hello world` will be encoded as: +//! +//! ```text +//! +- len: u16 -+---- data ----+ +//! | \x00\x0b | hello world | +//! +------------+--------------+ +//! ``` +//! +//! [`FramedRead`]: struct.FramedRead.html +//! [`FramedWrite`]: struct.FramedWrite.html +//! [`AsyncRead`]: ../../trait.AsyncRead.html +//! [`AsyncWrite`]: ../../trait.AsyncWrite.html +//! [`Encoder`]: ../trait.Encoder.html +//! [`BytesMut`]: https://docs.rs/bytes/0.4/bytes/struct.BytesMut.html + use { - codec::{Decoder, Encoder, FramedRead, FramedWrite, Framed}, - io::{AsyncRead, AsyncWrite}, + codec::{ + Decoder, Encoder, FramedRead, FramedWrite, Framed + }, + io::{ + AsyncRead, AsyncWrite + }, }; use bytes::{Buf, BufMut, Bytes, BytesMut, IntoBuf}; diff --git a/src/codec/mod.rs b/src/codec/mod.rs new file mode 100644 index 000000000..cb0fc922d --- /dev/null +++ b/src/codec/mod.rs @@ -0,0 +1,26 @@ +//! Utilities for encoding and decoding frames. +//! +//! Contains adapters to go from streams of bytes, [`AsyncRead`] and +//! [`AsyncWrite`], to framed streams implementing [`Sink`] and [`Stream`]. +//! Framed streams are also known as [transports]. +//! +//! [`AsyncRead`]: ../io/trait.AsyncRead.html +//! [`AsyncWrite`]: ../io/trait.AsyncWrite.html +//! [`Sink`]: https://docs.rs/futures/0.1/futures/sink/trait.Sink.html +//! [`Stream`]: https://docs.rs/futures/0.1/futures/stream/trait.Stream.html +//! [transports]: https://tokio.rs/docs/going-deeper/frames/ + +pub use tokio_codec::{ + Decoder, + Encoder, + Framed, + FramedParts, + FramedRead, + FramedWrite, + BytesCodec, + LinesCodec, +}; + +pub mod length_delimited; + +pub use self::length_delimited::LengthDelimitedCodec; diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 000000000..1d6bfd3a7 --- /dev/null +++ b/src/io.rs @@ -0,0 +1,93 @@ +//! Asynchronous I/O. +//! +//! This module is the asynchronous version of `std::io`. Primarily, it +//! defines two traits, [`AsyncRead`] and [`AsyncWrite`], which extend the +//! `Read` and `Write` traits of the standard library. +//! +//! # AsyncRead and AsyncWrite +//! +//! [`AsyncRead`] and [`AsyncWrite`] must only be implemented for +//! non-blocking I/O types that integrate with the futures type system. In +//! other words, these types must never block the thread, and instead the +//! current task is notified when the I/O resource is ready. +//! +//! # Standard input and output +//! +//! Tokio provides asynchronous APIs to standard [input], [output], and [error]. +//! These APIs are very similar to the ones provided by `std`, but they also +//! implement [`AsyncRead`] and [`AsyncWrite`]. +//! +//! Unlike *most* other Tokio APIs, the standard input / output APIs +//! **must** be used from the context of the Tokio runtime as they require +//! Tokio specific features to function. +//! +//! [input]: fn.stdin.html +//! [output]: fn.stdout.html +//! [error]: fn.stderr.html +//! +//! # Utility functions +//! +//! Utilities functions are provided for working with [`AsyncRead`] / +//! [`AsyncWrite`] types. For example, [`copy`] asynchronously copies all +//! data from a source to a destination. +//! +//! # `std` re-exports +//! +//! Additionally, [`Read`], [`Write`], [`Error`], [`ErrorKind`], and +//! [`Result`] are re-exported from `std::io` for ease of use. +//! +//! [`AsyncRead`]: trait.AsyncRead.html +//! [`AsyncWrite`]: trait.AsyncWrite.html +//! [`copy`]: fn.copy.html +//! [`Read`]: trait.Read.html +//! [`Write`]: trait.Write.html +//! [`Error`]: struct.Error.html +//! [`ErrorKind`]: enum.ErrorKind.html +//! [`Result`]: type.Result.html + +pub use tokio_io::{ + AsyncRead, + AsyncWrite, +}; + +// standard input, output, and error +pub use tokio_fs::{ + stdin, + Stdin, + stdout, + Stdout, + stderr, + Stderr, +}; + +// Utils +pub use tokio_io::io::{ + copy, + Copy, + flush, + Flush, + lines, + Lines, + read_exact, + ReadExact, + read_to_end, + ReadToEnd, + read_until, + ReadUntil, + ReadHalf, + shutdown, + Shutdown, + write_all, + WriteAll, + WriteHalf, +}; + +// Re-export io::Error so that users don't have to deal +// with conflicts when `use`ing `futures::io` and `std::io`. +pub use ::std::io::{ + Error, + ErrorKind, + Result, + Read, + Write, +}; diff --git a/src/lib.rs b/src/lib.rs index cbe8e0860..1f6693c71 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,9 +94,12 @@ extern crate tokio_async_await; extern crate tokio_uds; pub mod clock; +pub mod codec; pub mod executor; pub mod fs; +pub mod io; pub mod net; +pub mod prelude; pub mod reactor; pub mod runtime; pub mod timer; @@ -105,544 +108,7 @@ pub mod util; pub use executor::spawn; pub use runtime::run; -mod length_delimited; - -pub mod codec { - //! Utilities for encoding and decoding frames. - //! - //! Contains adapters to go from streams of bytes, [`AsyncRead`] and - //! [`AsyncWrite`], to framed streams implementing [`Sink`] and [`Stream`]. - //! Framed streams are also known as [transports]. - //! - //! [`AsyncRead`]: ../io/trait.AsyncRead.html - //! [`AsyncWrite`]: ../io/trait.AsyncWrite.html - //! [`Sink`]: https://docs.rs/futures/0.1/futures/sink/trait.Sink.html - //! [`Stream`]: https://docs.rs/futures/0.1/futures/stream/trait.Stream.html - //! [transports]: https://tokio.rs/docs/going-deeper/frames/ - - pub use tokio_codec::{ - Decoder, - Encoder, - Framed, - FramedParts, - FramedRead, - FramedWrite, - BytesCodec, - LinesCodec, - }; - - pub mod length_delimited { - //! Frame a stream of bytes based on a length prefix - //! - //! Many protocols delimit their frames by prefacing frame data with a - //! frame head that specifies the length of the frame. The - //! `length_delimited` module provides utilities for handling the length - //! based framing. This allows the consumer to work with entire frames - //! without having to worry about buffering or other framing logic. - //! - //! # Getting started - //! - //! If implementing a protocol from scratch, using length delimited framing - //! is an easy way to get started. [`Codec::new()`] will return a length - //! delimited codec using default configuration values. This can then be - //! used to construct a framer to adapt a full-duplex byte stream into a - //! stream of frames. - //! - //! ``` - //! # extern crate tokio; - //! use tokio::io::{AsyncRead, AsyncWrite}; - //! use tokio::codec::*; - //! - //! fn bind_transport(io: T) - //! -> Framed - //! { - //! Framed::new(io, LengthDelimitedCodec::new()) - //! } - //! # pub fn main() {} - //! ``` - //! - //! The returned transport implements `Sink + Stream` for `BytesMut`. It - //! encodes the frame with a big-endian `u32` header denoting the frame - //! payload length: - //! - //! ```text - //! +----------+--------------------------------+ - //! | len: u32 | frame payload | - //! +----------+--------------------------------+ - //! ``` - //! - //! Specifically, given the following: - //! - //! ``` - //! # extern crate tokio; - //! # extern crate bytes; - //! # extern crate futures; - //! # - //! use tokio::io::{AsyncRead, AsyncWrite}; - //! use tokio::codec::*; - //! use bytes::Bytes; - //! use futures::{Sink, Future}; - //! - //! fn write_frame(io: T) { - //! let mut transport = Framed::new(io, LengthDelimitedCodec::new()); - //! let frame = Bytes::from("hello world"); - //! - //! transport.send(frame).wait().unwrap(); - //! } - //! # - //! # pub fn main() {} - //! ``` - //! - //! The encoded frame will look like this: - //! - //! ```text - //! +---- len: u32 ----+---- data ----+ - //! | \x00\x00\x00\x0b | hello world | - //! +------------------+--------------+ - //! ``` - //! - //! # Decoding - //! - //! [`FramedRead`] adapts an [`AsyncRead`] into a `Stream` of [`BytesMut`], - //! such that each yielded [`BytesMut`] value contains the contents of an - //! entire frame. There are many configuration parameters enabling - //! [`FramedRead`] to handle a wide range of protocols. Here are some - //! examples that will cover the various options at a high level. - //! - //! ## Example 1 - //! - //! The following will parse a `u16` length field at offset 0, including the - //! frame head in the yielded `BytesMut`. - //! - //! ``` - //! # extern crate tokio; - //! # use tokio::io::AsyncRead; - //! # use tokio::codec::length_delimited; - //! # fn bind_read(io: T) { - //! length_delimited::Builder::new() - //! .length_field_offset(0) // default value - //! .length_field_length(2) - //! .length_adjustment(0) // default value - //! .num_skip(0) // Do not strip frame header - //! .new_read(io); - //! # } - //! # pub fn main() {} - //! ``` - //! - //! The following frame will be decoded as such: - //! - //! ```text - //! INPUT DECODED - //! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+ - //! | \x00\x0B | Hello world | --> | \x00\x0B | Hello world | - //! +----------+---------------+ +----------+---------------+ - //! ``` - //! - //! The value of the length field is 11 (`\x0B`) which represents the length - //! of the payload, `hello world`. By default, [`FramedRead`] assumes that - //! the length field represents the number of bytes that **follows** the - //! length field. Thus, the entire frame has a length of 13: 2 bytes for the - //! frame head + 11 bytes for the payload. - //! - //! ## Example 2 - //! - //! The following will parse a `u16` length field at offset 0, omitting the - //! frame head in the yielded `BytesMut`. - //! - //! ``` - //! # extern crate tokio; - //! # use tokio::io::AsyncRead; - //! # use tokio::codec::length_delimited; - //! # fn bind_read(io: T) { - //! length_delimited::Builder::new() - //! .length_field_offset(0) // default value - //! .length_field_length(2) - //! .length_adjustment(0) // default value - //! // `num_skip` is not needed, the default is to skip - //! .new_read(io); - //! # } - //! # pub fn main() {} - //! ``` - //! - //! The following frame will be decoded as such: - //! - //! ```text - //! INPUT DECODED - //! +-- len ---+--- Payload ---+ +--- Payload ---+ - //! | \x00\x0B | Hello world | --> | Hello world | - //! +----------+---------------+ +---------------+ - //! ``` - //! - //! This is similar to the first example, the only difference is that the - //! frame head is **not** included in the yielded `BytesMut` value. - //! - //! ## Example 3 - //! - //! The following will parse a `u16` length field at offset 0, including the - //! frame head in the yielded `BytesMut`. In this case, the length field - //! **includes** the frame head length. - //! - //! ``` - //! # extern crate tokio; - //! # use tokio::io::AsyncRead; - //! # use tokio::codec::length_delimited; - //! # fn bind_read(io: T) { - //! length_delimited::Builder::new() - //! .length_field_offset(0) // default value - //! .length_field_length(2) - //! .length_adjustment(-2) // size of head - //! .num_skip(0) - //! .new_read(io); - //! # } - //! # pub fn main() {} - //! ``` - //! - //! The following frame will be decoded as such: - //! - //! ```text - //! INPUT DECODED - //! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+ - //! | \x00\x0D | Hello world | --> | \x00\x0D | Hello world | - //! +----------+---------------+ +----------+---------------+ - //! ``` - //! - //! In most cases, the length field represents the length of the payload - //! only, as shown in the previous examples. However, in some protocols the - //! length field represents the length of the whole frame, including the - //! head. In such cases, we specify a negative `length_adjustment` to adjust - //! the value provided in the frame head to represent the payload length. - //! - //! ## Example 4 - //! - //! The following will parse a 3 byte length field at offset 0 in a 5 byte - //! frame head, including the frame head in the yielded `BytesMut`. - //! - //! ``` - //! # extern crate tokio; - //! # use tokio::io::AsyncRead; - //! # use tokio::codec::length_delimited; - //! # fn bind_read(io: T) { - //! length_delimited::Builder::new() - //! .length_field_offset(0) // default value - //! .length_field_length(3) - //! .length_adjustment(2) // remaining head - //! .num_skip(0) - //! .new_read(io); - //! # } - //! # pub fn main() {} - //! ``` - //! - //! The following frame will be decoded as such: - //! - //! ```text - //! INPUT - //! +---- len -----+- head -+--- Payload ---+ - //! | \x00\x00\x0B | \xCAFE | Hello world | - //! +--------------+--------+---------------+ - //! - //! DECODED - //! +---- len -----+- head -+--- Payload ---+ - //! | \x00\x00\x0B | \xCAFE | Hello world | - //! +--------------+--------+---------------+ - //! ``` - //! - //! A more advanced example that shows a case where there is extra frame - //! head data between the length field and the payload. In such cases, it is - //! usually desirable to include the frame head as part of the yielded - //! `BytesMut`. This lets consumers of the length delimited framer to - //! process the frame head as needed. - //! - //! The positive `length_adjustment` value lets `FramedRead` factor in the - //! additional head into the frame length calculation. - //! - //! ## Example 5 - //! - //! The following will parse a `u16` length field at offset 1 of a 4 byte - //! frame head. The first byte and the length field will be omitted from the - //! yielded `BytesMut`, but the trailing 2 bytes of the frame head will be - //! included. - //! - //! ``` - //! # extern crate tokio; - //! # use tokio::io::AsyncRead; - //! # use tokio::codec::length_delimited; - //! # fn bind_read(io: T) { - //! length_delimited::Builder::new() - //! .length_field_offset(1) // length of hdr1 - //! .length_field_length(2) - //! .length_adjustment(1) // length of hdr2 - //! .num_skip(3) // length of hdr1 + LEN - //! .new_read(io); - //! # } - //! # pub fn main() {} - //! ``` - //! - //! The following frame will be decoded as such: - //! - //! ```text - //! INPUT - //! +- hdr1 -+-- len ---+- hdr2 -+--- Payload ---+ - //! | \xCA | \x00\x0B | \xFE | Hello world | - //! +--------+----------+--------+---------------+ - //! - //! DECODED - //! +- hdr2 -+--- Payload ---+ - //! | \xFE | Hello world | - //! +--------+---------------+ - //! ``` - //! - //! The length field is situated in the middle of the frame head. In this - //! case, the first byte in the frame head could be a version or some other - //! identifier that is not needed for processing. On the other hand, the - //! second half of the head is needed. - //! - //! `length_field_offset` indicates how many bytes to skip before starting - //! to read the length field. `length_adjustment` is the number of bytes to - //! skip starting at the end of the length field. In this case, it is the - //! second half of the head. - //! - //! ## Example 6 - //! - //! The following will parse a `u16` length field at offset 1 of a 4 byte - //! frame head. The first byte and the length field will be omitted from the - //! yielded `BytesMut`, but the trailing 2 bytes of the frame head will be - //! included. In this case, the length field **includes** the frame head - //! length. - //! - //! ``` - //! # extern crate tokio; - //! # use tokio::io::AsyncRead; - //! # use tokio::codec::length_delimited; - //! # fn bind_read(io: T) { - //! length_delimited::Builder::new() - //! .length_field_offset(1) // length of hdr1 - //! .length_field_length(2) - //! .length_adjustment(-3) // length of hdr1 + LEN, negative - //! .num_skip(3) - //! .new_read(io); - //! # } - //! # pub fn main() {} - //! ``` - //! - //! The following frame will be decoded as such: - //! - //! ```text - //! INPUT - //! +- hdr1 -+-- len ---+- hdr2 -+--- Payload ---+ - //! | \xCA | \x00\x0F | \xFE | Hello world | - //! +--------+----------+--------+---------------+ - //! - //! DECODED - //! +- hdr2 -+--- Payload ---+ - //! | \xFE | Hello world | - //! +--------+---------------+ - //! ``` - //! - //! Similar to the example above, the difference is that the length field - //! represents the length of the entire frame instead of just the payload. - //! The length of `hdr1` and `len` must be counted in `length_adjustment`. - //! Note that the length of `hdr2` does **not** need to be explicitly set - //! anywhere because it already is factored into the total frame length that - //! is read from the byte stream. - //! - //! # Encoding - //! - //! [`FramedWrite`] adapts an [`AsyncWrite`] into a `Sink` of [`BytesMut`], - //! such that each submitted [`BytesMut`] is prefaced by a length field. - //! There are fewer configuration options than [`FramedRead`]. Given - //! protocols that have more complex frame heads, an encoder should probably - //! be written by hand using [`Encoder`]. - //! - //! Here is a simple example, given a `FramedWrite` with the following - //! configuration: - //! - //! ``` - //! # extern crate tokio; - //! # extern crate bytes; - //! # use tokio::io::AsyncWrite; - //! # use tokio::codec::length_delimited; - //! # use bytes::BytesMut; - //! # fn write_frame(io: T) { - //! # let _ = - //! length_delimited::Builder::new() - //! .length_field_length(2) - //! .new_write(io); - //! # } - //! # pub fn main() {} - //! ``` - //! - //! A payload of `hello world` will be encoded as: - //! - //! ```text - //! +- len: u16 -+---- data ----+ - //! | \x00\x0b | hello world | - //! +------------+--------------+ - //! ``` - //! - //! [`FramedRead`]: struct.FramedRead.html - //! [`FramedWrite`]: struct.FramedWrite.html - //! [`AsyncRead`]: ../../trait.AsyncRead.html - //! [`AsyncWrite`]: ../../trait.AsyncWrite.html - //! [`Encoder`]: ../trait.Encoder.html - //! [`BytesMut`]: https://docs.rs/bytes/0.4/bytes/struct.BytesMut.html - pub use ::length_delimited::*; - } - - pub use self::length_delimited::LengthDelimitedCodec; -} - -pub mod io { - //! Asynchronous I/O. - //! - //! This module is the asynchronous version of `std::io`. Primarily, it - //! defines two traits, [`AsyncRead`] and [`AsyncWrite`], which extend the - //! `Read` and `Write` traits of the standard library. - //! - //! # AsyncRead and AsyncWrite - //! - //! [`AsyncRead`] and [`AsyncWrite`] must only be implemented for - //! non-blocking I/O types that integrate with the futures type system. In - //! other words, these types must never block the thread, and instead the - //! current task is notified when the I/O resource is ready. - //! - //! # Standard input and output - //! - //! Tokio provides asynchronous APIs to standard [input], [output], and [error]. - //! These APIs are very similar to the ones provided by `std`, but they also - //! implement [`AsyncRead`] and [`AsyncWrite`]. - //! - //! Unlike *most* other Tokio APIs, the standard input / output APIs - //! **must** be used from the context of the Tokio runtime as they require - //! Tokio specific features to function. - //! - //! [input]: fn.stdin.html - //! [output]: fn.stdout.html - //! [error]: fn.stderr.html - //! - //! # Utility functions - //! - //! Utilities functions are provided for working with [`AsyncRead`] / - //! [`AsyncWrite`] types. For example, [`copy`] asynchronously copies all - //! data from a source to a destination. - //! - //! # `std` re-exports - //! - //! Additionally, [`Read`], [`Write`], [`Error`], [`ErrorKind`], and - //! [`Result`] are re-exported from `std::io` for ease of use. - //! - //! [`AsyncRead`]: trait.AsyncRead.html - //! [`AsyncWrite`]: trait.AsyncWrite.html - //! [`copy`]: fn.copy.html - //! [`Read`]: trait.Read.html - //! [`Write`]: trait.Write.html - //! [`Error`]: struct.Error.html - //! [`ErrorKind`]: enum.ErrorKind.html - //! [`Result`]: type.Result.html - - pub use tokio_io::{ - AsyncRead, - AsyncWrite, - }; - - // standard input, output, and error - pub use tokio_fs::{ - stdin, - Stdin, - stdout, - Stdout, - stderr, - Stderr, - }; - - // Utils - pub use tokio_io::io::{ - copy, - Copy, - flush, - Flush, - lines, - Lines, - read_exact, - ReadExact, - read_to_end, - ReadToEnd, - read_until, - ReadUntil, - ReadHalf, - shutdown, - Shutdown, - write_all, - WriteAll, - WriteHalf, - }; - - // Re-export io::Error so that users don't have to deal - // with conflicts when `use`ing `futures::io` and `std::io`. - pub use ::std::io::{ - Error, - ErrorKind, - Result, - Read, - Write, - }; -} - -pub mod prelude { - //! A "prelude" for users of the `tokio` crate. - //! - //! This prelude is similar to the standard library's prelude in that you'll - //! almost always want to import its entire contents, but unlike the standard - //! library's prelude you'll have to do so manually: - //! - //! ``` - //! use tokio::prelude::*; - //! ``` - //! - //! The prelude may grow over time as additional items see ubiquitous use. - - pub use tokio_io::{ - AsyncRead, - AsyncWrite, - }; - - pub use util::{ - FutureExt, - StreamExt, - }; - - pub use ::std::io::{ - Read, - Write, - }; - - pub use futures::{ - Future, - future, - Stream, - stream, - Sink, - IntoFuture, - Async, - AsyncSink, - Poll, - task, - }; - - #[cfg(feature = "async-await-preview")] - #[doc(inline)] - pub use tokio_async_await::{ - io::{ - AsyncReadExt, - AsyncWriteExt, - }, - sink::{ - SinkExt, - }, - stream::{ - StreamExt as StreamAsyncExt, - }, - }; -} +// ===== Experimental async/await support ===== #[cfg(feature = "async-await-preview")] mod async_await; diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 000000000..ecd82fe40 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,54 @@ +//! A "prelude" for users of the `tokio` crate. +//! +//! This prelude is similar to the standard library's prelude in that you'll +//! almost always want to import its entire contents, but unlike the standard +//! library's prelude you'll have to do so manually: +//! +//! ``` +//! use tokio::prelude::*; +//! ``` +//! +//! The prelude may grow over time as additional items see ubiquitous use. + +pub use tokio_io::{ + AsyncRead, + AsyncWrite, +}; + +pub use util::{ + FutureExt, + StreamExt, +}; + +pub use ::std::io::{ + Read, + Write, +}; + +pub use futures::{ + Future, + future, + Stream, + stream, + Sink, + IntoFuture, + Async, + AsyncSink, + Poll, + task, +}; + +#[cfg(feature = "async-await-preview")] +#[doc(inline)] +pub use tokio_async_await::{ + io::{ + AsyncReadExt, + AsyncWriteExt, + }, + sink::{ + SinkExt, + }, + stream::{ + StreamExt as StreamAsyncExt, + }, +};