summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tokio-io/src/codec
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/tokio-io/src/codec
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/tokio-io/src/codec')
-rw-r--r--third_party/rust/tokio-io/src/codec/bytes_codec.rs40
-rw-r--r--third_party/rust/tokio-io/src/codec/decoder.rs117
-rw-r--r--third_party/rust/tokio-io/src/codec/encoder.rs26
-rw-r--r--third_party/rust/tokio-io/src/codec/lines_codec.rs92
-rw-r--r--third_party/rust/tokio-io/src/codec/mod.rs376
5 files changed, 651 insertions, 0 deletions
diff --git a/third_party/rust/tokio-io/src/codec/bytes_codec.rs b/third_party/rust/tokio-io/src/codec/bytes_codec.rs
new file mode 100644
index 0000000000..c77f5ca530
--- /dev/null
+++ b/third_party/rust/tokio-io/src/codec/bytes_codec.rs
@@ -0,0 +1,40 @@
+#![allow(deprecated)]
+
+use bytes::{Bytes, BufMut, BytesMut};
+use codec::{Encoder, Decoder};
+use std::io;
+
+/// A simple `Codec` implementation that just ships bytes around.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
+pub struct BytesCodec(());
+
+impl BytesCodec {
+ /// Creates a new `BytesCodec` for shipping around raw bytes.
+ pub fn new() -> BytesCodec { BytesCodec(()) }
+}
+
+impl Decoder for BytesCodec {
+ type Item = BytesMut;
+ type Error = io::Error;
+
+ fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<BytesMut>, io::Error> {
+ if buf.len() > 0 {
+ let len = buf.len();
+ Ok(Some(buf.split_to(len)))
+ } else {
+ Ok(None)
+ }
+ }
+}
+
+impl Encoder for BytesCodec {
+ type Item = Bytes;
+ type Error = io::Error;
+
+ fn encode(&mut self, data: Bytes, buf: &mut BytesMut) -> Result<(), io::Error> {
+ buf.reserve(data.len());
+ buf.put(data);
+ Ok(())
+ }
+}
diff --git a/third_party/rust/tokio-io/src/codec/decoder.rs b/third_party/rust/tokio-io/src/codec/decoder.rs
new file mode 100644
index 0000000000..9797fb0d03
--- /dev/null
+++ b/third_party/rust/tokio-io/src/codec/decoder.rs
@@ -0,0 +1,117 @@
+use std::io;
+use bytes::BytesMut;
+
+use {AsyncWrite, AsyncRead};
+use super::encoder::Encoder;
+
+use ::_tokio_codec::Framed;
+
+/// Decoding of frames via buffers.
+///
+/// This trait is used when constructing an instance of `Framed` or
+/// `FramedRead`. An implementation of `Decoder` takes a byte stream that has
+/// already been buffered in `src` and decodes the data into a stream of
+/// `Self::Item` frames.
+///
+/// Implementations are able to track state on `self`, which enables
+/// implementing stateful streaming parsers. In many cases, though, this type
+/// will simply be a unit struct (e.g. `struct HttpDecoder`).
+
+// Note: We can't deprecate this trait, because the deprecation carries through to tokio-codec, and
+// there doesn't seem to be a way to un-deprecate the re-export.
+pub trait Decoder {
+ /// The type of decoded frames.
+ type Item;
+
+ /// The type of unrecoverable frame decoding errors.
+ ///
+ /// If an individual message is ill-formed but can be ignored without
+ /// interfering with the processing of future messages, it may be more
+ /// useful to report the failure as an `Item`.
+ ///
+ /// `From<io::Error>` is required in the interest of making `Error` suitable
+ /// for returning directly from a `FramedRead`, and to enable the default
+ /// implementation of `decode_eof` to yield an `io::Error` when the decoder
+ /// fails to consume all available data.
+ ///
+ /// Note that implementors of this trait can simply indicate `type Error =
+ /// io::Error` to use I/O errors as this type.
+ type Error: From<io::Error>;
+
+ /// Attempts to decode a frame from the provided buffer of bytes.
+ ///
+ /// This method is called by `FramedRead` whenever bytes are ready to be
+ /// parsed. The provided buffer of bytes is what's been read so far, and
+ /// this instance of `Decode` can determine whether an entire frame is in
+ /// the buffer and is ready to be returned.
+ ///
+ /// If an entire frame is available, then this instance will remove those
+ /// bytes from the buffer provided and return them as a decoded
+ /// frame. Note that removing bytes from the provided buffer doesn't always
+ /// necessarily copy the bytes, so this should be an efficient operation in
+ /// most circumstances.
+ ///
+ /// If the bytes look valid, but a frame isn't fully available yet, then
+ /// `Ok(None)` is returned. This indicates to the `Framed` instance that
+ /// it needs to read some more bytes before calling this method again.
+ ///
+ /// Note that the bytes provided may be empty. If a previous call to
+ /// `decode` consumed all the bytes in the buffer then `decode` will be
+ /// called again until it returns `None`, indicating that more bytes need to
+ /// be read.
+ ///
+ /// 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: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error>;
+
+ /// A default method available to be called when there are no more bytes
+ /// available to be read from the underlying I/O.
+ ///
+ /// This method defaults to calling `decode` and returns an error if
+ /// `Ok(None)` is returned while there is unconsumed data in `buf`.
+ /// Typically this doesn't need to be implemented unless the framing
+ /// protocol differs near the end of the stream.
+ ///
+ /// Note that the `buf` argument may be empty. If a previous call to
+ /// `decode_eof` consumed all the bytes in the buffer, `decode_eof` will be
+ /// called again until it returns `None`, indicating that there are no more
+ /// frames to yield. This behavior enables returning finalization frames
+ /// that may not be based on inbound data.
+ fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
+ match try!(self.decode(buf)) {
+ Some(frame) => Ok(Some(frame)),
+ None => {
+ if buf.is_empty() {
+ Ok(None)
+ } else {
+ Err(io::Error::new(io::ErrorKind::Other,
+ "bytes remaining on stream").into())
+ }
+ }
+ }
+ }
+
+ /// Provides a `Stream` and `Sink` interface for reading and writing to this
+ /// `Io` object, using `Decode` and `Encode` to read and write the raw data.
+ ///
+ /// Raw I/O objects work with byte sequences, but higher-level code usually
+ /// wants to batch these into meaningful chunks, called "frames". This
+ /// method layers framing on top of an I/O object, by using the `Codec`
+ /// traits 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 like gzip or TLS, 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 `Framed` returned by this method, which will
+ /// break them into separate objects, allowing them to interact more easily.
+ fn framed<T: AsyncRead + AsyncWrite + Sized>(self, io: T) -> Framed<T, Self>
+ where Self: Encoder + Sized,
+ {
+ Framed::new(io, self)
+ }
+}
diff --git a/third_party/rust/tokio-io/src/codec/encoder.rs b/third_party/rust/tokio-io/src/codec/encoder.rs
new file mode 100644
index 0000000000..222990d2e3
--- /dev/null
+++ b/third_party/rust/tokio-io/src/codec/encoder.rs
@@ -0,0 +1,26 @@
+use std::io;
+use bytes::BytesMut;
+
+/// Trait of helper objects to write out messages as bytes, for use with
+/// `FramedWrite`.
+
+// Note: We can't deprecate this trait, because the deprecation carries through to tokio-codec, and
+// there doesn't seem to be a way to un-deprecate the re-export.
+pub trait Encoder {
+ /// The type of items consumed by the `Encoder`
+ type Item;
+
+ /// The type of encoding errors.
+ ///
+ /// `FramedWrite` requires `Encoder`s errors to implement `From<io::Error>`
+ /// in the interest letting it return `Error`s directly.
+ type Error: From<io::Error>;
+
+ /// Encodes a frame into the buffer provided.
+ ///
+ /// This method will encode `item` into the byte buffer provided by `dst`.
+ /// The `dst` provided is an internal buffer of the `Framed` instance and
+ /// will be written out when possible.
+ fn encode(&mut self, item: Self::Item, dst: &mut BytesMut)
+ -> Result<(), Self::Error>;
+}
diff --git a/third_party/rust/tokio-io/src/codec/lines_codec.rs b/third_party/rust/tokio-io/src/codec/lines_codec.rs
new file mode 100644
index 0000000000..7056d5c8cd
--- /dev/null
+++ b/third_party/rust/tokio-io/src/codec/lines_codec.rs
@@ -0,0 +1,92 @@
+#![allow(deprecated)]
+
+use bytes::{BufMut, BytesMut};
+use codec::{Encoder, Decoder};
+use std::{io, str};
+
+/// A simple `Codec` implementation that splits up data into lines.
+#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[deprecated(since = "0.1.7", note = "Moved to tokio-codec")]
+pub struct LinesCodec {
+ // Stored index of the next index to examine for a `\n` character.
+ // This is used to optimize searching.
+ // For example, if `decode` was called with `abc`, it would hold `3`,
+ // because that is the next index to examine.
+ // The next time `decode` is called with `abcde\n`, the method will
+ // only look at `de\n` before returning.
+ next_index: usize,
+}
+
+impl LinesCodec {
+ /// Returns a `LinesCodec` for splitting up data into lines.
+ pub fn new() -> LinesCodec {
+ LinesCodec { next_index: 0 }
+ }
+}
+
+fn utf8(buf: &[u8]) -> Result<&str, io::Error> {
+ str::from_utf8(buf).map_err(|_|
+ io::Error::new(
+ io::ErrorKind::InvalidData,
+ "Unable to decode input as UTF8"))
+}
+
+fn without_carriage_return(s: &[u8]) -> &[u8] {
+ if let Some(&b'\r') = s.last() {
+ &s[..s.len() - 1]
+ } else {
+ s
+ }
+}
+
+impl Decoder for LinesCodec {
+ type Item = String;
+ type Error = io::Error;
+
+ fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<String>, io::Error> {
+ if let Some(newline_offset) =
+ buf[self.next_index..].iter().position(|b| *b == b'\n')
+ {
+ let newline_index = newline_offset + self.next_index;
+ let line = buf.split_to(newline_index + 1);
+ let line = &line[..line.len()-1];
+ let line = without_carriage_return(line);
+ let line = utf8(line)?;
+ self.next_index = 0;
+ Ok(Some(line.to_string()))
+ } else {
+ self.next_index = buf.len();
+ Ok(None)
+ }
+ }
+
+ fn decode_eof(&mut self, buf: &mut BytesMut) -> Result<Option<String>, io::Error> {
+ Ok(match self.decode(buf)? {
+ Some(frame) => Some(frame),
+ None => {
+ // No terminating newline - return remaining data, if any
+ if buf.is_empty() || buf == &b"\r"[..] {
+ None
+ } else {
+ let line = buf.take();
+ let line = without_carriage_return(&line);
+ let line = utf8(line)?;
+ self.next_index = 0;
+ Some(line.to_string())
+ }
+ }
+ })
+ }
+}
+
+impl Encoder for LinesCodec {
+ type Item = String;
+ type Error = io::Error;
+
+ fn encode(&mut self, line: String, buf: &mut BytesMut) -> Result<(), io::Error> {
+ buf.reserve(line.len() + 1);
+ buf.put(line);
+ buf.put_u8(b'\n');
+ Ok(())
+ }
+}
diff --git a/third_party/rust/tokio-io/src/codec/mod.rs b/third_party/rust/tokio-io/src/codec/mod.rs
new file mode 100644
index 0000000000..c4dab65647
--- /dev/null
+++ b/third_party/rust/tokio-io/src/codec/mod.rs
@@ -0,0 +1,376 @@
+//! 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`]: #
+//! [`AsyncWrite`]: #
+//! [`Sink`]: #
+//! [`Stream`]: #
+//! [transports]: #
+
+// tokio_io::codec originally held all codec-related helpers. This is now intended to be in
+// tokio_codec instead. However, for backward compatibility, this remains here. When the next major
+// breaking change comes, `Encoder` and `Decoder` need to be moved to `tokio_codec`, and the rest
+// of this module should be removed.
+
+#![doc(hidden)]
+#![allow(deprecated)]
+
+mod decoder;
+mod encoder;
+mod bytes_codec;
+mod lines_codec;
+
+pub use self::decoder::Decoder;
+pub use self::encoder::Encoder;
+pub use self::bytes_codec::BytesCodec;
+pub use self::lines_codec::LinesCodec;
+
+pub use framed::{Framed, FramedParts};
+pub use framed_read::FramedRead;
+pub use framed_write::FramedWrite;
+
+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. [`Framed::new()`] will adapt a
+ //! full-duplex byte stream with a length delimited framer using default
+ //! configuration values.
+ //!
+ //! ```
+ //! use tokio_io::{AsyncRead, AsyncWrite};
+ //! use tokio_io::codec::length_delimited;
+ //!
+ //! fn bind_transport<T: AsyncRead + AsyncWrite>(io: T)
+ //! -> length_delimited::Framed<T>
+ //! {
+ //! length_delimited::Framed::new(io)
+ //! }
+ //! ```
+ //!
+ //! 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_io;
+ //! # extern crate bytes;
+ //! # extern crate futures;
+ //! #
+ //! use tokio_io::{AsyncRead, AsyncWrite};
+ //! use tokio_io::codec::length_delimited;
+ //! use bytes::BytesMut;
+ //! use futures::{Sink, Future};
+ //!
+ //! fn write_frame<T: AsyncRead + AsyncWrite>(io: T) {
+ //! let mut transport = length_delimited::Framed::new(io);
+ //! let frame = BytesMut::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
+ //! [`FrameRead`] 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`.
+ //!
+ //! ```
+ //! # use tokio_io::AsyncRead;
+ //! # use tokio_io::codec::length_delimited;
+ //! # fn bind_read<T: AsyncRead>(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);
+ //! # }
+ //! ```
+ //!
+ //! 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`.
+ //!
+ //! ```
+ //! # use tokio_io::AsyncRead;
+ //! # use tokio_io::codec::length_delimited;
+ //! # fn bind_read<T: AsyncRead>(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);
+ //! # }
+ //! ```
+ //!
+ //! 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.
+ //!
+ //! ```
+ //! # use tokio_io::AsyncRead;
+ //! # use tokio_io::codec::length_delimited;
+ //! # fn bind_read<T: AsyncRead>(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);
+ //! # }
+ //! ```
+ //!
+ //! 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`.
+ //!
+ //! ```
+ //! # use tokio_io::AsyncRead;
+ //! # use tokio_io::codec::length_delimited;
+ //! # fn bind_read<T: AsyncRead>(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);
+ //! # }
+ //! ```
+ //!
+ //! 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.
+ //!
+ //! ```
+ //! # use tokio_io::AsyncRead;
+ //! # use tokio_io::codec::length_delimited;
+ //! # fn bind_read<T: AsyncRead>(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);
+ //! # }
+ //! ```
+ //!
+ //! 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.
+ //!
+ //! ```
+ //! # use tokio_io::AsyncRead;
+ //! # use tokio_io::codec::length_delimited;
+ //! # fn bind_read<T: AsyncRead>(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);
+ //! # }
+ //! ```
+ //!
+ //! 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_io;
+ //! # extern crate bytes;
+ //! # use tokio_io::AsyncWrite;
+ //! # use tokio_io::codec::length_delimited;
+ //! # use bytes::BytesMut;
+ //! # fn write_frame<T: AsyncWrite>(io: T) {
+ //! # let _: length_delimited::FramedWrite<T, BytesMut> =
+ //! 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::*;
+}