codec: fix broken length_delimited builder doc examples (#8350)

The Builder::new, new_codec, and new_read doc examples combined
length_adjustment(0) with num_skip(0). This leaves the length
header bytes in the buffer without accounting for them, so decoding
returns a frame that includes the raw header at the front and is
short at the back, corrupting the following frame.

Drop num_skip(0) so the default (skip the header) behavior applies,
and turn all three examples into executable doctests that perform a
real encode/decode round-trip and assert on the payload, so this
class of bug is caught automatically going forward.

Fixes: #8348
This commit is contained in:
GuTS805
2026-08-09 17:31:23 +02:00
committed by GitHub
parent e10d614cb9
commit b6ed00435d
+25 -13
View File
@@ -679,18 +679,21 @@ impl Builder {
/// # Examples
///
/// ```
/// # use tokio::io::AsyncRead;
/// use tokio_util::codec::LengthDelimitedCodec;
/// use tokio_stream::StreamExt;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// LengthDelimitedCodec::builder()
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() {
/// let io: &[u8] = b"\x00\x0bhello world";
/// let mut reader = LengthDelimitedCodec::builder()
/// .length_field_offset(0)
/// .length_field_type::<u16>()
/// .length_adjustment(0)
/// .num_skip(0)
/// .new_read(io);
///
/// let frame = reader.next().await.unwrap().unwrap();
/// assert_eq!(&frame[..], b"hello world");
/// # }
/// # pub fn main() {}
/// ```
pub fn new() -> Builder {
Builder {
@@ -953,14 +956,20 @@ impl Builder {
/// # Examples
///
/// ```
/// use tokio_util::codec::LengthDelimitedCodec;
/// use bytes::{Bytes, BytesMut};
/// use tokio_util::codec::{Decoder, Encoder, LengthDelimitedCodec};
///
/// # pub fn main() {
/// LengthDelimitedCodec::builder()
/// let mut codec = LengthDelimitedCodec::builder()
/// .length_field_offset(0)
/// .length_field_type::<u16>()
/// .length_adjustment(0)
/// .num_skip(0)
/// .new_codec();
///
/// let mut buf = BytesMut::new();
/// codec.encode(Bytes::from_static(b"hello world"), &mut buf).unwrap();
/// let frame = codec.decode(&mut buf).unwrap().unwrap();
/// assert_eq!(&frame[..], b"hello world");
/// # }
/// ```
pub fn new_codec(&self) -> LengthDelimitedCodec {
@@ -979,18 +988,21 @@ impl Builder {
/// # Examples
///
/// ```
/// # use tokio::io::AsyncRead;
/// use tokio_util::codec::LengthDelimitedCodec;
/// use tokio_stream::StreamExt;
///
/// # fn bind_read<T: AsyncRead>(io: T) {
/// LengthDelimitedCodec::builder()
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() {
/// let io: &[u8] = b"\x00\x0bhello world";
/// let mut reader = LengthDelimitedCodec::builder()
/// .length_field_offset(0)
/// .length_field_type::<u16>()
/// .length_adjustment(0)
/// .num_skip(0)
/// .new_read(io);
///
/// let frame = reader.next().await.unwrap().unwrap();
/// assert_eq!(&frame[..], b"hello world");
/// # }
/// # pub fn main() {}
/// ```
pub fn new_read<T>(&self, upstream: T) -> FramedRead<T, LengthDelimitedCodec>
where