Skip to main content

ntex_bytes/
lib.rs

1//! Provides abstractions for working with bytes.
2//!
3//! The crate provides immutable [`Bytes`] and mutable [`BytesMut`] buffers,
4//! UTF-8 [`ByteString`] values, paged buffers through [`BytePages`], and the
5//! [`Buf`] and [`BufMut`] traits.
6//!
7//! # `Bytes`
8//!
9//! `Bytes` is an efficient container for storing and operating on contiguous
10//! slices of memory. It is intended for use primarily in networking code, but
11//! could have applications elsewhere as well.
12//!
13//! `Bytes` values facilitate zero-copy network programming by allowing multiple
14//! `Bytes` objects to point to the same underlying memory. This is managed by
15//! using a reference count to track when the memory is no longer needed and can
16//! be freed.
17//!
18//! A common pattern is to write into a [`BytesMut`] and extract immutable
19//! [`Bytes`] views:
20//!
21//! ```rust
22//! use ntex_bytes::{BytesMut, BufMut};
23//!
24//! let mut buf = BytesMut::with_capacity(1024);
25//! buf.put(&b"hello world"[..]);
26//! buf.put_u16(1234);
27//!
28//! let a = buf.take();
29//! assert_eq!(a, b"hello world\x04\xD2"[..]);
30//!
31//! buf.put(&b"goodbye world"[..]);
32//!
33//! let b = buf.take();
34//! assert_eq!(b, b"goodbye world"[..]);
35//!
36//! assert_eq!(buf.capacity(), 998);
37//! ```
38//!
39//! In this example, a single 1,024-byte allocation is reused. The `a` and `b`
40//! handles retain immutable views into that allocation, while `buf` continues
41//! using its remaining capacity.
42//!
43//! See [`Bytes`] and [`BytesMut`] for details about sharing, splitting, and
44//! allocation behavior.
45//!
46//! # Interoperability
47//!
48//! [`Bytes`] and [`BytesMut`] implement the [`Buf`](::bytes::Buf) trait of the
49//! `bytes` crate, and [`BytesMut`] also implements its
50//! [`BufMut`](::bytes::BufMut) trait. [`Bytes`] and [`ByteString`] implement
51//! `serde`'s `Serialize` and `Deserialize`.
52//!
53//! # Crate features
54//!
55//! - `simd` enables SIMD-accelerated UTF-8 validation.
56//! - `overuse` enables diagnostic logging for unusually large page stacks.
57#![doc(html_root_url = "https://docs.rs/ntex-bytes/")]
58#![deny(clippy::pedantic)]
59#![allow(
60    unsafe_op_in_unsafe_fn,
61    clippy::cast_sign_loss,
62    clippy::cast_possible_wrap,
63    clippy::cast_possible_truncation,
64    clippy::must_use_candidate,
65    clippy::unnecessary_wraps
66)]
67
68extern crate alloc;
69
70#[macro_use]
71mod macros;
72
73pub mod buf;
74pub use crate::buf::{Buf, BufMut};
75
76mod bvec;
77mod bytes;
78mod debug;
79mod hex;
80mod pages;
81mod serde;
82mod storage;
83mod string;
84mod stvec;
85
86mod stext;
87mod stext_arc;
88
89pub use crate::bvec::BytesMut;
90pub use crate::bytes::Bytes;
91pub use crate::pages::{BytePage, BytePages};
92pub use crate::stext::{StorageExt, StorageExtStr, StorageVTable};
93pub use crate::string::ByteString;
94
95#[doc(hidden)]
96pub use crate::stvec::METADATA_SIZE;
97
98#[doc(hidden)]
99#[deprecated]
100pub type BytesVec = BytesMut;
101
102#[doc(hidden)]
103pub mod info {
104    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
105    pub struct Info {
106        pub id: usize,
107        pub refs: u32,
108        pub kind: Kind,
109        pub capacity: usize,
110    }
111
112    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
113    pub enum Kind {
114        Inline,
115        Static,
116        Vec,
117        StExt,
118    }
119
120    /// Storage backing a [`BytePage`](crate::BytePage).
121    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
122    pub enum PageKind {
123        /// Backed by `Bytes`, cloning shares the data.
124        Bytes,
125        /// Backed by `BytesMut` storage, cloning shares the data.
126        Storage,
127        /// Backed by `Vec<u8>`, cloning or splitting copies the data.
128        Vec,
129    }
130}
131
132/// Capacity category used when allocating [`BytePage`] storage.
133#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
134pub enum BytePageSize {
135    /// A 4 KiB page.
136    Size4 = 0,
137    /// An 8 KiB page.
138    Size8 = 1,
139    /// A 16 KiB page.
140    #[default]
141    Size16 = 2,
142    /// A 24 KiB page.
143    Size24 = 3,
144    /// A 32 KiB page.
145    Size32 = 4,
146    /// A 48 KiB page.
147    Size48 = 5,
148    /// A 64 KiB page.
149    Size64 = 6,
150    /// No fixed page category.
151    ///
152    /// Buffers of this category are sized on demand and never returned to
153    /// the page cache. It cannot be used as the page size of
154    /// [`BytePages`].
155    Unset = 7,
156}
157
158impl BytePageSize {
159    /// Returns the page capacity in bytes.
160    ///
161    /// A page is allocated together with its header, the capacity is the
162    /// category size minus the header, so the allocation is exactly the
163    /// category size and fits the allocator's size classes.
164    pub const fn capacity(self) -> usize {
165        self.alloc_size() - stvec::METADATA_SIZE
166    }
167
168    const fn alloc_size(self) -> usize {
169        match self {
170            BytePageSize::Size4 => 4 * 1024,
171            BytePageSize::Size8 => 8 * 1024,
172            BytePageSize::Size16 => 16 * 1024,
173            BytePageSize::Size24 => 24 * 1024,
174            BytePageSize::Size32 => 32 * 1024,
175            BytePageSize::Size48 => 48 * 1024,
176            BytePageSize::Size64 | BytePageSize::Unset => 64 * 1024,
177        }
178    }
179
180    /// Returns the recommended write-buffer threshold for this page size.
181    ///
182    /// This is half of the category size, but at most 16 KiB.
183    pub const fn half_capacity(self) -> usize {
184        match self {
185            BytePageSize::Size4 => 2 * 1024,
186            BytePageSize::Size8 => 4 * 1024,
187            BytePageSize::Size16 => 8 * 1024,
188            BytePageSize::Size24 => 12 * 1024,
189            BytePageSize::Size32
190            | BytePageSize::Size48
191            | BytePageSize::Size64
192            | BytePageSize::Unset => 16 * 1024,
193        }
194    }
195}
196
197/// Sets the maximum number of cached page allocations per page size for the
198/// current thread, the default is 16.
199///
200/// This setting affects only the thread on which it is called.
201pub fn set_pages_cache(size: usize) {
202    self::stvec::set_pages_cache(size);
203}
204
205#[cfg(test)]
206mod tests {
207    use super::*;
208
209    #[test]
210    fn page_size() {
211        const META: usize = stvec::METADATA_SIZE;
212        assert_eq!(BytePageSize::Size4.capacity(), 4 * 1024 - META);
213        assert_eq!(BytePageSize::Size8.capacity(), 8 * 1024 - META);
214        assert_eq!(BytePageSize::Size16.capacity(), 16 * 1024 - META);
215        assert_eq!(BytePageSize::Size24.capacity(), 24 * 1024 - META);
216        assert_eq!(BytePageSize::Size32.capacity(), 32 * 1024 - META);
217        assert_eq!(BytePageSize::Size48.capacity(), 48 * 1024 - META);
218        assert_eq!(BytePageSize::Size64.capacity(), 64 * 1024 - META);
219        assert_eq!(BytePageSize::Unset.capacity(), 64 * 1024 - META);
220        assert_eq!(BytePageSize::Size4.half_capacity(), 2 * 1024);
221        assert_eq!(BytePageSize::Size8.half_capacity(), 4 * 1024);
222        assert_eq!(BytePageSize::Size16.half_capacity(), 8 * 1024);
223        assert_eq!(BytePageSize::Size24.half_capacity(), 12 * 1024);
224        assert_eq!(BytePageSize::Size32.half_capacity(), 16 * 1024);
225        assert_eq!(BytePageSize::Size48.half_capacity(), 16 * 1024);
226        assert_eq!(BytePageSize::Size64.half_capacity(), 16 * 1024);
227        assert_eq!(BytePageSize::Unset.half_capacity(), 16 * 1024);
228    }
229}