bytes/lib.rs
1#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
2#![doc(test(
3 no_crate_inject,
4 attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
5))]
6#![no_std]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8
9//! Provides abstractions for working with bytes.
10//!
11//! The `bytes` crate provides an efficient byte buffer structure
12//! ([`Bytes`]) and traits for working with buffer
13//! implementations ([`Buf`], [`BufMut`]).
14//!
15//! # `Bytes`
16//!
17//! `Bytes` is an efficient container for storing and operating on contiguous
18//! slices of memory. It is intended for use primarily in networking code, but
19//! could have applications elsewhere as well.
20//!
21//! `Bytes` values facilitate zero-copy network programming by allowing multiple
22//! `Bytes` objects to point to the same underlying memory. This is managed by
23//! using a reference count to track when the memory is no longer needed and can
24//! be freed.
25//!
26//! A `Bytes` handle can be created directly from an existing byte store (such as `&[u8]`
27//! or `Vec<u8>`), but usually a `BytesMut` is used first and written to. For
28//! example:
29//!
30//! ```rust
31//! use bytes::{BytesMut, BufMut};
32//!
33//! let mut buf = BytesMut::with_capacity(1024);
34//! buf.put(&b"hello world"[..]);
35//! buf.put_u16(1234);
36//!
37//! let a = buf.split();
38//! assert_eq!(a, b"hello world\x04\xD2"[..]);
39//!
40//! buf.put(&b"goodbye world"[..]);
41//!
42//! let b = buf.split();
43//! assert_eq!(b, b"goodbye world"[..]);
44//!
45//! assert_eq!(buf.capacity(), 998);
46//! ```
47//!
48//! In the above example, only a single buffer of 1024 is allocated. The handles
49//! `a` and `b` will share the underlying buffer and maintain indices tracking
50//! the view into the buffer represented by the handle.
51//!
52//! See the [struct docs](`Bytes`) for more details.
53//!
54//! # `Buf`, `BufMut`
55//!
56//! These two traits provide read and write access to buffers. The underlying
57//! storage may or may not be in contiguous memory. For example, `Bytes` is a
58//! buffer that guarantees contiguous memory, but a [rope] stores the bytes in
59//! disjoint chunks. `Buf` and `BufMut` maintain cursors tracking the current
60//! position in the underlying byte storage. When bytes are read or written, the
61//! cursor is advanced.
62//!
63//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure)
64//!
65//! ## Relation with `Read` and `Write`
66//!
67//! At first glance, it may seem that `Buf` and `BufMut` overlap in
68//! functionality with [`std::io::Read`] and [`std::io::Write`]. However, they
69//! serve different purposes. A buffer is the value that is provided as an
70//! argument to `Read::read` and `Write::write`. `Read` and `Write` may then
71//! perform a syscall, which has the potential of failing. Operations on `Buf`
72//! and `BufMut` are infallible.
73
74extern crate alloc;
75
76#[cfg(feature = "std")]
77extern crate std;
78
79pub mod buf;
80pub use crate::buf::{Buf, BufMut};
81
82mod bytes;
83mod bytes_mut;
84mod fmt;
85mod loom;
86pub use crate::bytes::Bytes;
87pub use crate::bytes_mut::BytesMut;
88
89// Optional Serde support
90#[cfg(feature = "serde")]
91mod serde;
92
93#[inline(never)]
94#[cold]
95fn abort() -> ! {
96 #[cfg(feature = "std")]
97 {
98 std::process::abort();
99 }
100
101 #[cfg(not(feature = "std"))]
102 {
103 struct Abort;
104 impl Drop for Abort {
105 fn drop(&mut self) {
106 panic!();
107 }
108 }
109 let _a = Abort;
110 panic!("abort");
111 }
112}
113
114#[inline(always)]
115#[cfg(feature = "std")]
116fn saturating_sub_usize_u64(a: usize, b: u64) -> usize {
117 match usize::try_from(b) {
118 Ok(b) => a.saturating_sub(b),
119 Err(_) => 0,
120 }
121}
122
123#[inline(always)]
124#[cfg(feature = "std")]
125fn min_u64_usize(a: u64, b: usize) -> usize {
126 match usize::try_from(a) {
127 Ok(a) => usize::min(a, b),
128 Err(_) => b,
129 }
130}
131
132/// Performs bounds checking of a range.
133///
134/// This is a spiritual copy of [core::slice::index::range] because that
135/// function is currently unstable.
136#[inline(always)]
137#[track_caller]
138fn range(range: impl core::ops::RangeBounds<usize>, len: usize) -> (usize, usize) {
139 use core::ops::Bound;
140
141 let begin = match range.start_bound() {
142 Bound::Included(&n) => n,
143 Bound::Excluded(&n) => n.checked_add(1).expect("out of range"),
144 Bound::Unbounded => 0,
145 };
146
147 let end = match range.end_bound() {
148 Bound::Included(&n) => n.checked_add(1).expect("out of range"),
149 Bound::Excluded(&n) => n,
150 Bound::Unbounded => len,
151 };
152
153 assert!(
154 begin <= end,
155 "range start must not be greater than end: {:?} <= {:?}",
156 begin,
157 end,
158 );
159 assert!(
160 end <= len,
161 "range end out of bounds: {:?} <= {:?}",
162 end,
163 len,
164 );
165
166 (begin, end)
167}
168
169/// Error type for the `try_get_` methods of [`Buf`].
170/// Indicates that there were not enough remaining
171/// bytes in the buffer while attempting
172/// to get a value from a [`Buf`] with one
173/// of the `try_get_` methods.
174#[derive(Debug, PartialEq, Eq)]
175pub struct TryGetError {
176 /// The number of bytes necessary to get the value
177 pub requested: usize,
178
179 /// The number of bytes available in the buffer
180 pub available: usize,
181}
182
183impl core::fmt::Display for TryGetError {
184 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
185 write!(
186 f,
187 "Not enough bytes remaining in buffer to read value (requested {} but only {} available)",
188 self.requested,
189 self.available
190 )
191 }
192}
193
194#[cfg(feature = "std")]
195impl std::error::Error for TryGetError {}
196
197#[cfg(feature = "std")]
198impl From<TryGetError> for std::io::Error {
199 fn from(error: TryGetError) -> Self {
200 std::io::Error::new(std::io::ErrorKind::Other, error)
201 }
202}
203
204/// Panic with a nice error message.
205#[cold]
206fn panic_advance(error_info: &TryGetError) -> ! {
207 panic!(
208 "advance out of bounds: the len is {} but advancing by {}",
209 error_info.available, error_info.requested
210 );
211}
212
213#[cold]
214fn panic_does_not_fit(size: usize, nbytes: usize) -> ! {
215 panic!(
216 "size too large: the integer type can fit {} bytes, but nbytes is {}",
217 size, nbytes
218 );
219}