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