diff --git a/tokio-util/src/codec/length_delimited.rs b/tokio-util/src/codec/length_delimited.rs index c37f5863b..c1f24167a 100644 --- a/tokio-util/src/codec/length_delimited.rs +++ b/tokio-util/src/codec/length_delimited.rs @@ -75,55 +75,23 @@ //! //! ## 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_util::codec::LengthDelimitedCodec; -//! # fn bind_read(io: T) { -//! LengthDelimitedCodec::builder() -//! .length_field_offset(0) // default value -//! .length_field_type::() -//! .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`. //! //! ``` -//! # use tokio::io::AsyncRead; +//! # use tokio_stream::StreamExt; //! # use tokio_util::codec::LengthDelimitedCodec; -//! # fn bind_read(io: T) { -//! LengthDelimitedCodec::builder() +//! # #[tokio::main] +//! # async fn main() { +//! # let io: &[u8] = b"\x00\x0BHello world"; +//! let mut reader = LengthDelimitedCodec::builder() //! .length_field_offset(0) // default value //! .length_field_type::() //! .length_adjustment(0) // default value -//! // `num_skip` is not needed, the default is to skip //! .new_read(io); +//! # let res = reader.next().await.unwrap().unwrap().to_vec(); +//! # assert_eq!(res, b"Hello world"); //! # } -//! # pub fn main() {} //! ``` //! //! The following frame will be decoded as such: @@ -135,27 +103,32 @@ //! +----------+---------------+ +---------------+ //! ``` //! -//! This is similar to the first example, the only difference is that the -//! frame head is **not** included in the yielded `BytesMut` value. +//! 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 3 +//! ## Example 2 //! //! 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. +//! frame head in the yielded `BytesMut`. //! //! ``` -//! # use tokio::io::AsyncRead; +//! # use tokio_stream::StreamExt; //! # use tokio_util::codec::LengthDelimitedCodec; -//! # fn bind_read(io: T) { -//! LengthDelimitedCodec::builder() +//! # #[tokio::main] +//! # async fn main() { +//! # let io: &[u8] = b"\x00\x0BHello world"; +//! let mut reader = LengthDelimitedCodec::builder() //! .length_field_offset(0) // default value //! .length_field_type::() -//! .length_adjustment(-2) // size of head -//! .num_skip(0) +//! .length_adjustment(2) // Add head size to length +//! .num_skip(0) // Do NOT skip the head //! .new_read(io); +//! # let res = reader.next().await.unwrap().unwrap().to_vec(); +//! # assert_eq!(res, b"\x00\x0BHello world"); //! # } -//! # pub fn main() {} //! ``` //! //! The following frame will be decoded as such: @@ -163,10 +136,46 @@ //! ```text //! INPUT DECODED //! +-- len ---+--- Payload ---+ +-- len ---+--- Payload ---+ -//! | \x00\x0D | Hello world | --> | \x00\x0D | Hello world | +//! | \x00\x0B | Hello world | --> | \x00\x0B | Hello world | //! +----------+---------------+ +----------+---------------+ //! ``` //! +//! This is similar to the first example, the only difference is that the +//! frame head is **included** in the yielded `BytesMut` value. To achieve +//! this, we need to add the header size to the length with `length_adjustment`, +//! and set `num_skip` to `0` to prevent skipping the head. +//! +//! ## Example 3 +//! +//! The following will parse a `u16` length field at offset 0, omitting the +//! frame head in the yielded `BytesMut`. In this case, the length field +//! **includes** the frame head length. +//! +//! ``` +//! # use tokio_stream::StreamExt; +//! # use tokio_util::codec::LengthDelimitedCodec; +//! # #[tokio::main] +//! # async fn main() { +//! # let io: &[u8] = b"\x00\x0DHello world"; +//! let mut reader = LengthDelimitedCodec::builder() +//! .length_field_offset(0) // default value +//! .length_field_type::() +//! .length_adjustment(-2) // size of head +//! .new_read(io); +//! # let res = reader.next().await.unwrap().unwrap().to_vec(); +//! # assert_eq!(res, b"Hello world"); +//! # } +//! ``` +//! +//! The following frame will be decoded as such: +//! +//! ```text +//! INPUT DECODED +//! +-- len ---+--- Payload ---+ +--- Payload ---+ +//! | \x00\x0D | Hello world | --> | 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 @@ -179,17 +188,20 @@ //! frame head, including the frame head in the yielded `BytesMut`. //! //! ``` -//! # use tokio::io::AsyncRead; +//! # use tokio_stream::StreamExt; //! # use tokio_util::codec::LengthDelimitedCodec; -//! # fn bind_read(io: T) { -//! LengthDelimitedCodec::builder() +//! # #[tokio::main] +//! # async fn main() { +//! # let io: &[u8] = b"\x00\x00\x0B\xCA\xFEHello world"; +//! let mut reader = LengthDelimitedCodec::builder() //! .length_field_offset(0) // default value //! .length_field_length(3) -//! .length_adjustment(2) // remaining head +//! .length_adjustment(3 + 2) // len field and remaining head //! .num_skip(0) //! .new_read(io); +//! # let res = reader.next().await.unwrap().unwrap().to_vec(); +//! # assert_eq!(res, b"\x00\x00\x0B\xCA\xFEHello world"); //! # } -//! # pub fn main() {} //! ``` //! //! The following frame will be decoded as such: @@ -223,17 +235,20 @@ //! included. //! //! ``` -//! # use tokio::io::AsyncRead; +//! # use tokio_stream::StreamExt; //! # use tokio_util::codec::LengthDelimitedCodec; -//! # fn bind_read(io: T) { -//! LengthDelimitedCodec::builder() +//! # #[tokio::main] +//! # async fn main() { +//! # let io: &[u8] = b"\xCA\x00\x0B\xFEHello world"; +//! let mut reader = LengthDelimitedCodec::builder() //! .length_field_offset(1) // length of hdr1 //! .length_field_type::() //! .length_adjustment(1) // length of hdr2 //! .num_skip(3) // length of hdr1 + LEN //! .new_read(io); +//! # let res = reader.next().await.unwrap().unwrap().to_vec(); +//! # assert_eq!(res, b"\xFEHello world"); //! # } -//! # pub fn main() {} //! ``` //! //! The following frame will be decoded as such: @@ -269,15 +284,19 @@ //! length. //! //! ``` -//! # use tokio::io::AsyncRead; +//! # use tokio_stream::StreamExt; //! # use tokio_util::codec::LengthDelimitedCodec; -//! # fn bind_read(io: T) { -//! LengthDelimitedCodec::builder() +//! # #[tokio::main] +//! # async fn main() { +//! # let io: &[u8] = b"\xCA\x00\x0F\xFEHello world"; +//! let mut reader = LengthDelimitedCodec::builder() //! .length_field_offset(1) // length of hdr1 //! .length_field_type::() //! .length_adjustment(-3) // length of hdr1 + LEN, negative //! .num_skip(3) //! .new_read(io); +//! # let res = reader.next().await.unwrap().unwrap().to_vec(); +//! # assert_eq!(res, b"\xFEHello world"); //! # } //! ``` //! @@ -308,17 +327,20 @@ //! frame head, excluding the 4th byte from the yielded `BytesMut`. //! //! ``` -//! # use tokio::io::AsyncRead; +//! # use tokio_stream::StreamExt; //! # use tokio_util::codec::LengthDelimitedCodec; -//! # fn bind_read(io: T) { -//! LengthDelimitedCodec::builder() +//! # #[tokio::main] +//! # async fn main() { +//! # let io: &[u8] = b"\x00\x00\x0B\xFFHello world"; +//! let mut reader = LengthDelimitedCodec::builder() //! .length_field_offset(0) // default value //! .length_field_length(3) //! .length_adjustment(0) // default value //! .num_skip(4) // skip the first 4 bytes //! .new_read(io); +//! # let res = reader.next().await.unwrap().unwrap().to_vec(); +//! # assert_eq!(res, b"Hello world"); //! # } -//! # pub fn main() {} //! ``` //! //! The following frame will be decoded as such: