bytes_pool/lib.rs
1//! A pool for creating byte-slices and strings that can be cheaply cloned and shared across threads
2//! without allocating memory. Byte-slices are shared as [`Bytes`], and strings are shared as
3//! [`ByteString`]s.
4//!
5//! Internally, a `BytesPool` is a wrapper around a [`BytesMut`] buffer from the [`bytes`] crate.
6//! It shares data by appending the data to its buffer and then splitting the buffer off with
7//! [`BytesMut::split`]. This only allocates memory if the buffer needs to resize.
8
9#![no_std]
10
11pub use bytes::Bytes;
12pub use bytestring::ByteString;
13
14use bytes::BytesMut;
15
16/// A pool for creating byte-slices and strings that can be cheaply cloned and shared across threads
17/// without allocating memory. Byte-slices are shared as [`Bytes`], and strings are shared as
18/// [`ByteString`]s.
19///
20/// Internally, a `BytesPool` is a wrapper around a [`BytesMut`] buffer from the [`bytes`] crate.
21/// It shares data by appending the data to its buffer and then splitting the buffer off with
22/// [`BytesMut::split`]. This only allocates memory if the buffer needs to resize.
23#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct BytesPool {
25 inner: BytesMut,
26}
27
28impl BytesPool {
29 /// Creates a new `BytesPool` with default capacity.
30 ///
31 /// Resulting object has unspecified capacity.
32 /// This function does not allocate.
33 ///
34 /// # Examples
35 ///
36 /// ```
37 /// use bytes_pool::BytesPool;
38 ///
39 /// let mut pool = BytesPool::new();
40 /// ```
41 #[inline]
42 pub fn new() -> Self {
43 Self {
44 inner: BytesMut::new(),
45 }
46 }
47
48 /// Creates a new `BytesPool` with the specified capacity.
49 ///
50 /// The returned `BytesPool` will be able to hold at least `capacity` bytes
51 /// without reallocating.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// use bytes_pool::BytesPool;
57 ///
58 /// let mut pool = BytesPool::with_capacity(64);
59 /// ```
60 #[inline]
61 pub fn with_capacity(capacity: usize) -> Self {
62 Self {
63 inner: BytesMut::with_capacity(capacity),
64 }
65 }
66
67 /// Returns the number of bytes the `BytesPool` can hold without reallocating.
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use bytes_pool::BytesPool;
73 ///
74 /// let b = BytesPool::with_capacity(64);
75 /// assert_eq!(b.capacity(), 64);
76 /// ```
77 #[inline]
78 pub fn capacity(&self) -> usize {
79 self.inner.capacity()
80 }
81
82 /// Creates an immutable slice of bytes that can be shared across threads and cheaply cloned.
83 ///
84 /// No allocation is performed unless the internal buffer needs to be resized to accomodate
85 /// the additional bytes.
86 ///
87 /// # Examples
88 ///
89 /// ```
90 /// use bytes_pool::BytesPool;
91 ///
92 /// let mut pool = BytesPool::with_capacity(64);
93 ///
94 /// let bytes = pool.share_bytes(b"hello world");
95 ///
96 /// assert_eq!(bytes, &b"hello world"[..]);
97 /// ```
98 #[inline]
99 pub fn share_bytes(&mut self, bytes: &[u8]) -> Bytes {
100 self.inner.extend_from_slice(bytes);
101 self.inner.split().freeze()
102 }
103
104 /// Creates an immutable string that can be shared across threads and cheaply cloned.
105 ///
106 /// No allocation is performed unless the internal buffer needs to be resized to accomodate
107 /// the additional bytes.
108 ///
109 /// # Examples
110 ///
111 /// ```
112 /// use bytes_pool::BytesPool;
113 ///
114 /// let mut pool = BytesPool::with_capacity(64);
115 ///
116 /// let s = pool.share_str("hello world");
117 ///
118 /// assert_eq!(s, "hello world");
119 /// ```
120 #[inline]
121 pub fn share_str(&mut self, s: &str) -> ByteString {
122 let bytes = self.share_bytes(s.as_bytes());
123 // SAFETY: `self.inner` contains only valid UTF-8.
124 unsafe { ByteString::from_bytes_unchecked(bytes) }
125 }
126
127 /// Reserves capacity for at least `additional` bytes to be inserted
128 /// into the given `BytesPool`.
129 ///
130 /// More than `additional` bytes may be reserved in order to avoid frequent
131 /// reallocations. A call to `reserve` may result in an allocation.
132 ///
133 /// This function performs the same optimizations as [`BytesMut::reserve`].
134 ///
135 /// # Examples
136 ///
137 /// ```
138 /// use bytes_pool::BytesPool;
139 ///
140 /// let mut pool = BytesPool::with_capacity(128);
141 /// let bytes = pool.share_bytes(&[0; 64][..]);
142 ///
143 /// assert_eq!(pool.capacity(), 64);
144 ///
145 /// pool.reserve(128);
146 ///
147 /// assert_eq!(pool.capacity(), 128);
148 /// ```
149 ///
150 /// # Panics
151 ///
152 /// Panics if the new capacity overflows `usize`.
153 #[inline]
154 pub fn reserve(&mut self, additional: usize) {
155 self.inner.reserve(additional);
156 }
157
158 /// Attempts to cheaply reclaim already allocated capacity for at least `additional` more
159 /// bytes to be inserted into the given `BytesPool` and returns `true` if it succeeded.
160 ///
161 /// `try_reclaim` behaves exactly like [`reserve`](BytesPool::reserve), except that it never
162 /// allocates new storage and returns a `bool` indicating whether it was successful in doing
163 /// so:
164 ///
165 /// `try_reclaim` returns false under these conditions:
166 /// - The spare capacity left is less than `additional` bytes AND
167 /// - The existing allocation cannot be reclaimed cheaply or it was less than
168 /// `additional` bytes in size
169 ///
170 /// Reclaiming the allocation cheaply is possible if the `BytesPool` has no outstanding
171 /// references through `Bytes` or `ByteString`s which point to its underlying storage.
172 ///
173 /// # Examples
174 ///
175 /// ```
176 /// use bytes_pool::BytesPool;
177 ///
178 /// let mut pool = BytesPool::with_capacity(64);
179 /// assert_eq!(true, pool.try_reclaim(64));
180 /// assert_eq!(64, pool.capacity());
181 ///
182 /// let mut bytes = pool.share_bytes(b"abcd");
183 /// assert_eq!(60, pool.capacity());
184 /// assert_eq!(false, pool.try_reclaim(64));
185 /// // pool has capacity for 60 bytes
186 /// assert_eq!(true, pool.try_reclaim(60));
187 ///
188 /// drop(bytes);
189 ///
190 /// assert_eq!(true, pool.try_reclaim(64));
191 /// ```
192 #[inline]
193 #[must_use = "consider BytesPool::reserve if you need an infallible reservation"]
194 pub fn try_reclaim(&mut self, additional: usize) -> bool {
195 self.inner.try_reclaim(additional)
196 }
197}