bitvec/
boxed.rs

1#![cfg(feature = "alloc")]
2#![doc = include_str!("../doc/boxed.md")]
3
4use alloc::boxed::Box;
5use core::{
6	mem::ManuallyDrop,
7	slice,
8};
9
10use tap::{
11	Pipe,
12	Tap,
13};
14use wyz::comu::Mut;
15
16use crate::{
17	index::BitIdx,
18	mem,
19	order::{
20		BitOrder,
21		Lsb0,
22	},
23	ptr::{
24		BitPtr,
25		BitSpan,
26	},
27	slice::BitSlice,
28	store::BitStore,
29	vec::BitVec,
30	view::BitView,
31};
32
33mod api;
34mod iter;
35mod ops;
36mod tests;
37mod traits;
38
39pub use self::iter::IntoIter;
40
41#[repr(transparent)]
42#[doc = include_str!("../doc/boxed/BitBox.md")]
43pub struct BitBox<T = usize, O = Lsb0>
44where
45	T: BitStore,
46	O: BitOrder,
47{
48	/// Describes the region that the box owns.
49	bitspan: BitSpan<Mut, T, O>,
50}
51
52impl<T, O> BitBox<T, O>
53where
54	T: BitStore,
55	O: BitOrder,
56{
57	/// Copies a bit-slice region into a new bit-box allocation.
58	///
59	/// The referent memory is `memcpy`d into the heap, exactly preserving the
60	/// original bit-slice’s memory layout and contents. This allows the
61	/// function to run as fast as possible, but misaligned source bit-slices
62	/// may result in decreased performance or unexpected layout behavior during
63	/// use. You can use [`.force_align()`] to ensure that the referent
64	/// bit-slice is aligned in memory.
65	///
66	/// ## Notes
67	///
68	/// Bits in the allocation of the source bit-slice, but outside its own
69	/// description of that memory, have an **unspecified**, but initialized,
70	/// value. You may not rely on their contents in any way, and you *should*
71	/// call [`.force_align()`] and/or [`.fill_uninitialized()`] if you are
72	/// going to inspect the underlying memory of the new allocation.
73	///
74	/// ## Examples
75	///
76	/// ```rust
77	/// use bitvec::prelude::*;
78	///
79	/// let data = 0b0101_1011u8;
80	/// let bits = data.view_bits::<Msb0>();
81	/// let bb = BitBox::from_bitslice(&bits[2 ..]);
82	/// assert_eq!(bb, bits[2 ..]);
83	/// ```
84	///
85	/// [`.fill_uninitialized()`]: Self::fill_uninitialized
86	/// [`.force_align()`]: Self::force_align
87	#[inline]
88	pub fn from_bitslice(slice: &BitSlice<T, O>) -> Self {
89		BitVec::from_bitslice(slice).into_boxed_bitslice()
90	}
91
92	/// Converts a `Box<[T]>` into a `BitBox<T, O>`, in place.
93	///
94	/// This does not affect the referent buffer, and only transforms the
95	/// handle.
96	///
97	/// ## Panics
98	///
99	/// This panics if the provided `boxed` slice is too long to view as a
100	/// bit-slice region.
101	///
102	/// ## Examples
103	///
104	/// ```rust
105	/// use bitvec::prelude::*;
106	///
107	/// let boxed: Box<[u8]> = Box::new([0; 40]);
108	/// let addr = boxed.as_ptr();
109	/// let bb = BitBox::<u8>::from_boxed_slice(boxed);
110	/// assert_eq!(bb, bits![0; 320]);
111	/// assert_eq!(addr, bb.as_raw_slice().as_ptr());
112	/// ```
113	#[inline]
114	pub fn from_boxed_slice(boxed: Box<[T]>) -> Self {
115		Self::try_from_boxed_slice(boxed)
116			.expect("slice was too long to be converted into a `BitBox`")
117	}
118
119	/// Attempts to convert an ordinary boxed slice into a boxed bit-slice.
120	///
121	/// This does not perform a copy or reällocation; it only attempts to
122	/// transform the handle. Because `Box<[T]>` can be longer than `BitBox`es,
123	/// it may fail, and will return the original handle if it does.
124	///
125	/// It is unlikely that you have a single `Box<[_]>` that is too large to
126	/// convert into a bit-box. You can find the length restrictions as the
127	/// bit-slice associated constants [`MAX_BITS`] and [`MAX_ELTS`].
128	///
129	/// ## Examples
130	///
131	/// ```rust
132	/// use bitvec::prelude::*;
133	///
134	/// let boxed: Box<[u8]> = Box::new([0u8; 40]);
135	/// let addr = boxed.as_ptr();
136	/// let bb = BitBox::<u8>::try_from_boxed_slice(boxed).unwrap();
137	/// assert_eq!(bb, bits![0; 320]);
138	/// assert_eq!(addr, bb.as_raw_slice().as_ptr());
139	/// ```
140	///
141	/// [`MAX_BITS`]: crate::slice::BitSlice::MAX_BITS
142	/// [`MAX_ELTS`]: crate::slice::BitSlice::MAX_ELTS
143	#[inline]
144	pub fn try_from_boxed_slice(boxed: Box<[T]>) -> Result<Self, Box<[T]>> {
145		let mut boxed = ManuallyDrop::new(boxed);
146
147		BitPtr::from_mut_slice(boxed.as_mut())
148			.span(boxed.len() * mem::bits_of::<T::Mem>())
149			.map(|bitspan| Self { bitspan })
150			.map_err(|_| ManuallyDrop::into_inner(boxed))
151	}
152
153	/// Converts the bit-box back into an ordinary boxed element slice.
154	///
155	/// This does not touch the allocator or the buffer contents; it is purely a
156	/// handle transform.
157	///
158	/// ## Examples
159	///
160	/// ```rust
161	/// use bitvec::prelude::*;
162	///
163	/// let bb = bitbox![0; 5];
164	/// let addr = bb.as_raw_slice().as_ptr();
165	/// let boxed = bb.into_boxed_slice();
166	/// assert_eq!(boxed[..], [0][..]);
167	/// assert_eq!(addr, boxed.as_ptr());
168	/// ```
169	#[inline]
170	pub fn into_boxed_slice(self) -> Box<[T]> {
171		self.pipe(ManuallyDrop::new)
172			.as_raw_mut_slice()
173			.pipe(|slice| unsafe { Box::from_raw(slice) })
174	}
175
176	/// Converts the bit-box into a bit-vector.
177	///
178	/// This uses the Rust allocator API, and does not guarantee whether or not
179	/// a reällocation occurs internally.
180	///
181	/// The resulting bit-vector can be converted back into a bit-box via
182	/// [`BitBox::into_boxed_bitslice`][0].
183	///
184	/// ## Original
185	///
186	/// [`slice::into_vec`](https://doc.rust-lang.org/std/primitive.slice.html#method.into_vec)
187	///
188	/// ## API Differences
189	///
190	/// The original function is implemented in an `impl<T> [T]` block, despite
191	/// taking a `Box<[T]>` receiver. Since `BitBox` cannot be used as an
192	/// explicit receiver outside its own `impl` blocks, the method is relocated
193	/// here.
194	///
195	/// ## Examples
196	///
197	/// ```rust
198	/// use bitvec::prelude::*;
199	///
200	/// let bb = bitbox![0, 1, 0, 0, 1];
201	/// let bv = bb.into_bitvec();
202	///
203	/// assert_eq!(bv, bitvec![0, 1, 0, 0, 1]);
204	/// ```
205	///
206	/// [0]: crate::vec::BitVec::into_boxed_bitslice
207	#[inline]
208	pub fn into_bitvec(self) -> BitVec<T, O> {
209		let bitspan = self.bitspan;
210		/* This pipeline converts the underlying `Box<[T]>` into a `Vec<T>`,
211		 * then converts that into a `BitVec`. This handles any changes that
212		 * may occur in the allocator. Once done, the original head/span
213		 * values need to be written into the `BitVec`, since the conversion
214		 * from `Vec` always fully spans the live elements.
215		 */
216		self.pipe(ManuallyDrop::new)
217			.with_box(|b| unsafe { ManuallyDrop::take(b) })
218			.into_vec()
219			.pipe(BitVec::from_vec)
220			.tap_mut(|bv| unsafe {
221				// len first! Otherwise, the descriptor might briefly go out of
222				// bounds.
223				bv.set_len_unchecked(bitspan.len());
224				bv.set_head(bitspan.head());
225			})
226	}
227
228	/// Explicitly views the bit-box as a bit-slice.
229	#[inline]
230	pub fn as_bitslice(&self) -> &BitSlice<T, O> {
231		unsafe { self.bitspan.into_bitslice_ref() }
232	}
233
234	/// Explicitly views the bit-box as a mutable bit-slice.
235	#[inline]
236	pub fn as_mut_bitslice(&mut self) -> &mut BitSlice<T, O> {
237		unsafe { self.bitspan.into_bitslice_mut() }
238	}
239
240	/// Views the bit-box as a slice of its underlying memory elements.
241	///
242	/// Because bit-boxes uniquely own their buffer, they can safely view the
243	/// underlying buffer without dealing with contending neighbors.
244	#[inline]
245	pub fn as_raw_slice(&self) -> &[T] {
246		let (data, len) =
247			(self.bitspan.address().to_const(), self.bitspan.elements());
248		unsafe { slice::from_raw_parts(data, len) }
249	}
250
251	/// Views the bit-box as a mutable slice of its underlying memory elements.
252	///
253	/// Because bit-boxes uniquely own their buffer, they can safely view the
254	/// underlying buffer without dealing with contending neighbors.
255	#[inline]
256	pub fn as_raw_mut_slice(&mut self) -> &mut [T] {
257		let (data, len) =
258			(self.bitspan.address().to_mut(), self.bitspan.elements());
259		unsafe { slice::from_raw_parts_mut(data, len) }
260	}
261
262	/// Sets the unused bits outside the `BitBox` buffer to a fixed value.
263	///
264	/// This method modifies all bits that the allocated buffer owns but which
265	/// are outside the `self.as_bitslice()` view. `bitvec` guarantees that all
266	/// owned bits are initialized to *some* value, but does not guarantee
267	/// *which* value. This method can be used to make all such unused bits have
268	/// a known value after the call, so that viewing the underlying memory
269	/// directly has consistent results.
270	///
271	/// Note that the crate implementation guarantees that all bits owned by its
272	/// handles are stably initialized according to the language and compiler
273	/// rules! `bitvec` will never cause UB by using uninitialized memory.
274	///
275	/// ## Examples
276	///
277	/// ```rust
278	/// use bitvec::prelude::*;
279	///
280	/// let bits = 0b1011_0101u8.view_bits::<Msb0>();
281	/// let mut bb = BitBox::from_bitslice(&bits[2 .. 6]);
282	/// assert_eq!(bb.count_ones(), 3);
283	/// // Remember, the two bits on each edge are unspecified, and cannot be
284	/// // observed! They must be masked away for the test to be meaningful.
285	/// assert_eq!(bb.as_raw_slice()[0] & 0x3C, 0b00_1101_00u8);
286	///
287	/// bb.fill_uninitialized(false);
288	/// assert_eq!(bb.as_raw_slice(), &[0b00_1101_00u8]);
289	///
290	/// bb.fill_uninitialized(true);
291	/// assert_eq!(bb.as_raw_slice(), &[0b11_1101_11u8]);
292	/// ```
293	#[inline]
294	pub fn fill_uninitialized(&mut self, value: bool) {
295		let (_, head, bits) = self.bitspan.raw_parts();
296		let head = head.into_inner() as usize;
297		let tail = head + bits;
298		let all = self.as_raw_mut_slice().view_bits_mut::<O>();
299		unsafe {
300			all.get_unchecked_mut(.. head).fill(value);
301			all.get_unchecked_mut(tail ..).fill(value);
302		}
303	}
304
305	/// Ensures that the allocated buffer has no dead bits between the start of
306	/// the buffer and the start of the live bit-slice.
307	///
308	/// This is useful for ensuring a consistent memory layout in bit-boxes
309	/// created by cloning an arbitrary bit-slice into the heap. As bit-slices
310	/// can begin and end anywhere in memory, the [`::from_bitslice()`] function
311	/// does not attempt to normalize them and only does a fast element-wise
312	/// copy when creating the bit-box.
313	///
314	/// The value of dead bits that are in the allocation but not in the live
315	/// region are *initialized*, but do not have a *specified* value. After
316	/// calling this method, you should use [`.fill_uninitialized()`] to set the
317	/// excess bits in the buffer to a fixed value.
318	///
319	/// ## Examples
320	///
321	/// ```rust
322	/// use bitvec::prelude::*;
323	///
324	/// let bits = &0b10_1101_01u8.view_bits::<Msb0>()[2 .. 6];
325	/// let mut bb = BitBox::from_bitslice(bits);
326	/// // Remember, the two bits on each edge are unspecified, and cannot be
327	/// // observed! They must be masked away for the test to be meaningful.
328	/// assert_eq!(bb.as_raw_slice()[0] & 0x3C, 0b00_1101_00u8);
329	///
330	/// bb.force_align();
331	/// bb.fill_uninitialized(false);
332	/// assert_eq!(bb.as_raw_slice(), &[0b1101_0000u8]);
333	/// ```
334	///
335	/// [`::from_bitslice()`]: Self::from_bitslice
336	/// [`.fill_uninitialized()`]: Self::fill_uninitialized
337	#[inline]
338	pub fn force_align(&mut self) {
339		let head = self.bitspan.head();
340		if head == BitIdx::MIN {
341			return;
342		}
343		let head = head.into_inner() as usize;
344		let last = self.len() + head;
345		unsafe {
346			self.bitspan.set_head(BitIdx::MIN);
347			self.copy_within_unchecked(head .. last, 0);
348		}
349	}
350
351	/// Permits a function to modify the `Box` backing storage of a `BitBox`
352	/// handle.
353	///
354	/// This produces a temporary `Box` view of the bit-box’s buffer and allows
355	/// a function to have mutable access to it. After the callback returns, the
356	/// `Box` is written back into `self` and forgotten.
357	#[inline]
358	fn with_box<F, R>(&mut self, func: F) -> R
359	where F: FnOnce(&mut ManuallyDrop<Box<[T]>>) -> R {
360		self.as_raw_mut_slice()
361			.pipe(|raw| unsafe { Box::from_raw(raw) })
362			.pipe(ManuallyDrop::new)
363			.pipe_ref_mut(func)
364	}
365}