chunked_bytes/
lib.rs

1//! A non-contiguous buffer for efficient serialization of data structures
2//! and vectored output.
3//!
4//! This crate provides `ChunkedBytes`, a [rope]-like byte container based on
5//! `Bytes` and `BytesMut` from the `bytes` crate. Its primary purpose is to
6//! serve as an intermediate buffer for serializing fields of data structures
7//! into byte sequences of varying length, without whole-buffer reallocations
8//! like those performed to grow a `Vec`, and then consuming the bytes in bulk,
9//! split into regularly sized chunks suitable for [vectored output].
10//!
11//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
12//! [vectored output]: https://en.wikipedia.org/wiki/Vectored_I/O
13//!
14//! `ChunkedBytes` implements the traits `Buf` and `BufMut` for read and write
15//! access to the buffered data. It also provides the `put_bytes` method
16//! for appending a `Bytes` slice to its queue of non-contiguous chunks without
17//! copying the data.
18//!
19//! # Examples
20//!
21//! ```
22//! use bytes::{Buf, BufMut, Bytes};
23//! use chunked_bytes::ChunkedBytes;
24//! use std::io::{self, IoSlice, Read, Write};
25//! use std::net::{SocketAddr, TcpListener, TcpStream, Shutdown};
26//! use std::thread;
27//!
28//! fn write_vectored<W: Write>(
29//!     buf: &mut ChunkedBytes,
30//!     mut out: W,
31//! ) -> io::Result<usize> {
32//!     let mut io_bufs = [IoSlice::new(&[]); 32];
33//!     let io_vec_len = buf.chunks_vectored(&mut io_bufs);
34//!     let bytes_written = out.write_vectored(&io_bufs[..io_vec_len])?;
35//!     buf.advance(bytes_written);
36//!     Ok(bytes_written)
37//! }
38//!
39//! fn main() -> io::Result<()> {
40//!     const MESSAGE: &[u8] = b"I \xf0\x9f\x96\xa4 \x00\xc0\xff\xee";
41//!
42//!     let listen_addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap();
43//!     let server = TcpListener::bind(listen_addr)?;
44//!     let server_addr = server.local_addr()?;
45//!
46//!     let server_handle: thread::JoinHandle<io::Result<()>> =
47//!         thread::spawn(move || {
48//!             let (mut receiver, _) = server.accept()?;
49//!             let mut buf = Vec::with_capacity(64);
50//!             receiver.read_to_end(&mut buf)?;
51//!             assert_eq!(buf.as_slice(), MESSAGE);
52//!             Ok(())
53//!         });
54//!
55//!     let mut sender = TcpStream::connect(server_addr)?;
56//!
57//!     let mut buf = ChunkedBytes::with_chunk_size_hint(4096);
58//!
59//!     buf.put("I ".as_bytes());
60//!     buf.put_bytes(Bytes::from("🖤 "));
61//!     buf.put_u32(0xc0ffee);
62//!
63//!     let bytes_written = write_vectored(&mut buf, &mut sender)?;
64//!     assert_eq!(bytes_written, MESSAGE.len());
65//!
66//!     sender.shutdown(Shutdown::Write)?;
67//!
68//!     server_handle.join().expect("server thread panicked")?;
69//!     Ok(())
70//! }
71
72#![warn(clippy::all)]
73#![warn(future_incompatible)]
74#![warn(missing_docs)]
75#![warn(rust_2018_idioms)]
76#![doc(test(no_crate_inject, attr(deny(warnings, rust_2018_idioms))))]
77
78pub mod loosely;
79pub mod strictly;
80
81mod chunked;
82mod iter;
83
84pub use self::iter::{DrainChunks, IntoChunks};
85pub use self::loosely::ChunkedBytes;
86
87#[cfg(test)]
88mod tests;