aligned_buffer/
shared.rs

1use crate::{
2	alloc::{BufferAllocator, Global},
3	raw::RawAlignedBuffer,
4	UniqueAlignedBuffer, DEFAULT_BUFFER_ALIGNMENT,
5};
6use std::{fmt, ops, slice::SliceIndex};
7
8/// A shared buffer with an alignment. This buffer cannot be mutated.
9/// Typically, a `SharedAlignedBuffer` is created from a [`UniqueAlignedBuffer`].
10/// It can be cloned and shared across threads. It is effectively the same as an
11/// Arc<\[u8]>.
12pub struct SharedAlignedBuffer<const ALIGNMENT: usize = DEFAULT_BUFFER_ALIGNMENT, A = Global>
13where
14	A: BufferAllocator<ALIGNMENT>,
15{
16	pub(crate) buf: RawAlignedBuffer<ALIGNMENT, A>,
17}
18
19impl<const ALIGNMENT: usize, A> Default for SharedAlignedBuffer<ALIGNMENT, A>
20where
21	A: BufferAllocator<ALIGNMENT> + Default,
22{
23	#[inline]
24	#[must_use]
25	fn default() -> Self {
26		Self::new_in(A::default())
27	}
28}
29
30impl<const ALIGNMENT: usize> SharedAlignedBuffer<ALIGNMENT> {
31	/// Constructs a new, empty `SharedAlignedBuffer`.
32	///
33	/// The buffer will not allocate and cannot be mutated.
34	/// It's effectively the same as an empty slice.
35	///
36	/// # Examples
37	///
38	/// ```
39	/// # #![allow(unused_mut)]
40	/// # use aligned_buffer::SharedAlignedBuffer;
41	/// let buf = SharedAlignedBuffer::<32>::new();
42	/// ```
43	#[inline]
44	#[must_use]
45	pub const fn new() -> Self {
46		Self::new_in(Global)
47	}
48}
49
50impl<const ALIGNMENT: usize, A> SharedAlignedBuffer<ALIGNMENT, A>
51where
52	A: BufferAllocator<ALIGNMENT>,
53{
54	/// Constructs a new, empty `SharedAlignedBuffer`.
55	///
56	/// The buffer will not allocate and cannot be mutated.
57	/// It's effectively the same as an empty slice.
58	///
59	/// # Examples
60	///
61	/// ```
62	/// # #![allow(unused_mut)]
63	/// # use aligned_buffer::{SharedAlignedBuffer, alloc::Global};
64	/// let buf = SharedAlignedBuffer::<32>::new_in(Global);
65	/// ```
66	#[inline]
67	#[must_use]
68	pub const fn new_in(alloc: A) -> Self {
69		let buf = RawAlignedBuffer::new_in(alloc);
70		Self { buf }
71	}
72
73	/// Extracts a slice containing the entire buffer.
74	///
75	/// Equivalent to `&s[..]`.
76	///
77	/// # Examples
78	///
79	/// ```
80	/// # use aligned_buffer::{UniqueAlignedBuffer, SharedAlignedBuffer};
81	/// use std::io::{self, Write};
82	/// let mut buf = UniqueAlignedBuffer::<16>::with_capacity(10);
83	/// buf.extend([1, 2, 3, 5, 8]);
84	/// let buf = SharedAlignedBuffer::from(buf);
85	/// io::sink().write(buf.as_slice()).unwrap();
86	/// ```
87	#[inline]
88	pub fn as_slice(&self) -> &[u8] {
89		self
90	}
91
92	/// Returns a raw pointer to the buffer's data, or a dangling raw pointer
93	/// valid for zero sized reads if the vector didn't allocate.
94	///
95	/// The caller must ensure that the buffer outlives the pointer this
96	/// function returns, or else it will end up pointing to garbage.
97	/// Modifying the buffer may cause its buffer to be reallocated,
98	/// which would also make any pointers to it invalid.
99	///
100	/// This method guarantees that for the purpose of the aliasing model, this method
101	/// does not materialize a reference to the underlying slice, and thus the returned pointer
102	/// will remain valid when mixed with other calls to [`as_ptr`].
103	///
104	///
105	/// # Examples
106	///
107	/// ```
108	/// # use aligned_buffer::{UniqueAlignedBuffer, SharedAlignedBuffer};
109	/// let mut buf = UniqueAlignedBuffer::<16>::with_capacity(10);
110	/// buf.extend([1, 2, 4]);
111	/// let buf = SharedAlignedBuffer::from(buf);
112	/// let buf_ptr = buf.as_ptr();
113	///
114	/// unsafe {
115	///     for i in 0..buf.len() {
116	///         assert_eq!(*buf_ptr.add(i), 1 << i);
117	///     }
118	/// }
119	/// ```
120	///
121	/// [`as_ptr`]: SharedAlignedBuffer::as_ptr
122	#[inline]
123	pub fn as_ptr(&self) -> *const u8 {
124		// We shadow the slice method of the same name to avoid going through
125		// `deref`, which creates an intermediate reference.
126		self.buf.ptr()
127	}
128
129	/// Returns the number of elements in the buffer, also referred to
130	/// as its 'length'.
131	///
132	/// # Examples
133	///
134	/// ```
135	/// # use aligned_buffer::{UniqueAlignedBuffer, SharedAlignedBuffer};
136	/// let mut buf = UniqueAlignedBuffer::<16>::with_capacity(10);
137	/// buf.extend([1, 2, 3]);
138	/// let buf = SharedAlignedBuffer::from(buf);
139	/// assert_eq!(buf.len(), 3);
140	/// ```
141	#[inline]
142	pub fn len(&self) -> usize {
143		// when the buffer is shared, cap_or_len is the length
144		self.buf.cap_or_len()
145	}
146
147	/// Returns `true` if the buffer contains no data.
148	///
149	/// # Examples
150	///
151	/// ```
152	/// # use aligned_buffer::{UniqueAlignedBuffer, SharedAlignedBuffer};
153	/// let mut buf = UniqueAlignedBuffer::<16>::with_capacity(10);
154	/// buf.push(1);
155	/// let buf = SharedAlignedBuffer::from(buf);
156	/// assert!(!buf.is_empty());
157	/// ```
158	pub fn is_empty(&self) -> bool {
159		self.len() == 0
160	}
161
162	/// Whether or not the buffer is unique (i.e. is the only reference to the buffer).
163	#[inline]
164	pub fn is_unique(&self) -> bool {
165		self.buf.is_unique()
166	}
167
168	/// Returns the number of references to this buffer.
169	#[inline]
170	pub fn ref_count(&self) -> usize {
171		self.buf.ref_count()
172	}
173
174	/// Returns a [`UniqueAlignedBuffer`] if the [`SharedAlignedBuffer`] has exactly one reference.
175	///
176	/// Otherwise, an [`Err`] is returned with the same [`SharedAlignedBuffer`] that was
177	/// passed in.
178	///
179	/// # Examples
180	///
181	/// ```
182	/// # use aligned_buffer::{UniqueAlignedBuffer, SharedAlignedBuffer};
183	///
184	/// let buf = UniqueAlignedBuffer::<16>::from_iter([1, 2, 3, 4]).into_shared();
185	/// assert!(SharedAlignedBuffer::try_unique(buf).is_ok());
186	///
187	/// let x = UniqueAlignedBuffer::<16>::from_iter([1, 2, 3, 4]).into_shared();
188	/// let _y = SharedAlignedBuffer::clone(&x);
189	/// assert!(SharedAlignedBuffer::try_unique(x).is_err());
190	/// ```
191	pub fn try_unique(mut this: Self) -> Result<UniqueAlignedBuffer<ALIGNMENT, A>, Self> {
192		if this.is_unique() {
193			let len = this.len();
194			this.buf.reset_cap();
195			Ok(UniqueAlignedBuffer { buf: this.buf, len })
196		} else {
197			Err(this)
198		}
199	}
200}
201
202impl<const ALIGNMENT: usize, A> Clone for SharedAlignedBuffer<ALIGNMENT, A>
203where
204	A: BufferAllocator<ALIGNMENT> + Clone,
205{
206	fn clone(&self) -> Self {
207		Self {
208			buf: self.buf.ref_clone(),
209		}
210	}
211}
212
213impl<const ALIGNMENT: usize, A> From<UniqueAlignedBuffer<ALIGNMENT, A>>
214	for SharedAlignedBuffer<ALIGNMENT, A>
215where
216	A: BufferAllocator<ALIGNMENT>,
217{
218	#[inline]
219	fn from(buf: UniqueAlignedBuffer<ALIGNMENT, A>) -> Self {
220		buf.into_shared()
221	}
222}
223
224impl<const ALIGNMENT: usize, A> ops::Deref for SharedAlignedBuffer<ALIGNMENT, A>
225where
226	A: BufferAllocator<ALIGNMENT>,
227{
228	type Target = [u8];
229
230	#[inline]
231	fn deref(&self) -> &Self::Target {
232		unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }
233	}
234}
235
236impl<I: SliceIndex<[u8]>, const ALIGNMENT: usize, A> ops::Index<I>
237	for SharedAlignedBuffer<ALIGNMENT, A>
238where
239	A: BufferAllocator<ALIGNMENT>,
240{
241	type Output = I::Output;
242
243	#[inline]
244	fn index(&self, index: I) -> &Self::Output {
245		ops::Index::index(&**self, index)
246	}
247}
248
249impl<const ALIGNMENT: usize, A> fmt::Debug for SharedAlignedBuffer<ALIGNMENT, A>
250where
251	A: BufferAllocator<ALIGNMENT>,
252{
253	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254		fmt::Debug::fmt(&**self, f)
255	}
256}
257
258impl<const ALIGNMENT: usize, A> AsRef<[u8]> for SharedAlignedBuffer<ALIGNMENT, A>
259where
260	A: BufferAllocator<ALIGNMENT>,
261{
262	#[inline]
263	fn as_ref(&self) -> &[u8] {
264		self
265	}
266}
267
268#[cfg(feature = "stable-deref-trait")]
269unsafe impl<const ALIGNMENT: usize, A> stable_deref_trait::StableDeref
270	for SharedAlignedBuffer<ALIGNMENT, A>
271where
272	A: BufferAllocator<ALIGNMENT>,
273{
274}
275
276#[cfg(feature = "stable-deref-trait")]
277unsafe impl<const ALIGNMENT: usize, A> stable_deref_trait::CloneStableDeref
278	for SharedAlignedBuffer<ALIGNMENT, A>
279where
280	A: BufferAllocator<ALIGNMENT> + Clone,
281{
282}
283
284#[cfg(test)]
285mod tests {
286	use super::*;
287
288	#[test]
289	fn clones_returns_same_pointer() {
290		let mut buf = UniqueAlignedBuffer::<16>::with_capacity(10);
291		buf.extend([1, 2, 3]);
292		let buf = SharedAlignedBuffer::from(buf);
293		let buf2 = buf.clone();
294		assert_eq!(buf.as_ptr(), buf2.as_ptr());
295	}
296
297	#[test]
298	fn try_unique_returns_err_when_not_unique() {
299		let x = UniqueAlignedBuffer::<16>::from_iter([1, 2, 3, 4]).into_shared();
300		let _y = SharedAlignedBuffer::clone(&x);
301		assert!(SharedAlignedBuffer::try_unique(x).is_err());
302	}
303
304	#[test]
305	fn sharing_does_not_shrink_the_buffer() {
306		let buf = UniqueAlignedBuffer::<64>::with_capacity(10);
307		let cap = buf.capacity();
308		let buf = buf.into_shared();
309		assert_eq!(&*buf, &[]);
310
311		let buf = UniqueAlignedBuffer::try_from(buf).unwrap();
312		assert_eq!(&*buf, &[]);
313		assert_eq!(buf.capacity(), cap);
314	}
315
316	// Check that the `SharedAlignedBuffer` is `Send` and `Sync`.
317	const _: () = {
318		const fn assert_send_sync<T: Send + Sync>() {}
319		assert_send_sync::<SharedAlignedBuffer<16>>();
320	};
321}