Coverage Report

Created: 2025-07-01 06:28

/rust/registry/src/index.crates.io-6f17d22bba15001f/bitvec-1.0.1/src/boxed.rs
Line
Count
Source (jump to first uncovered line)
1
#![cfg(feature = "alloc")]
2
#![doc = include_str!("../doc/boxed.md")]
3
4
use alloc::boxed::Box;
5
use core::{
6
  mem::ManuallyDrop,
7
  slice,
8
};
9
10
use tap::{
11
  Pipe,
12
  Tap,
13
};
14
use wyz::comu::Mut;
15
16
use 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
33
mod api;
34
mod iter;
35
mod ops;
36
mod tests;
37
mod traits;
38
39
pub use self::iter::IntoIter;
40
41
#[repr(transparent)]
42
#[doc = include_str!("../doc/boxed/BitBox.md")]
43
pub struct BitBox<T = usize, O = Lsb0>
44
where
45
  T: BitStore,
46
  O: BitOrder,
47
{
48
  /// Describes the region that the box owns.
49
  bitspan: BitSpan<Mut, T, O>,
50
}
51
52
impl<T, O> BitBox<T, O>
53
where
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
0
  pub fn from_bitslice(slice: &BitSlice<T, O>) -> Self {
89
0
    BitVec::from_bitslice(slice).into_boxed_bitslice()
90
0
  }
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
0
  pub fn from_boxed_slice(boxed: Box<[T]>) -> Self {
115
0
    Self::try_from_boxed_slice(boxed)
116
0
      .expect("slice was too long to be converted into a `BitBox`")
117
0
  }
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
0
  pub fn try_from_boxed_slice(boxed: Box<[T]>) -> Result<Self, Box<[T]>> {
145
0
    let mut boxed = ManuallyDrop::new(boxed);
146
0
147
0
    BitPtr::from_mut_slice(boxed.as_mut())
148
0
      .span(boxed.len() * mem::bits_of::<T::Mem>())
149
0
      .map(|bitspan| Self { bitspan })
150
0
      .map_err(|_| ManuallyDrop::into_inner(boxed))
151
0
  }
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
0
  pub fn into_boxed_slice(self) -> Box<[T]> {
171
0
    self.pipe(ManuallyDrop::new)
172
0
      .as_raw_mut_slice()
173
0
      .pipe(|slice| unsafe { Box::from_raw(slice) })
174
0
  }
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
0
  pub fn into_bitvec(self) -> BitVec<T, O> {
209
0
    let bitspan = self.bitspan;
210
0
    /* This pipeline converts the underlying `Box<[T]>` into a `Vec<T>`,
211
0
     * then converts that into a `BitVec`. This handles any changes that
212
0
     * may occur in the allocator. Once done, the original head/span
213
0
     * values need to be written into the `BitVec`, since the conversion
214
0
     * from `Vec` always fully spans the live elements.
215
0
     */
216
0
    self.pipe(ManuallyDrop::new)
217
0
      .with_box(|b| unsafe { ManuallyDrop::take(b) })
218
0
      .into_vec()
219
0
      .pipe(BitVec::from_vec)
220
0
      .tap_mut(|bv| unsafe {
221
0
        // len first! Otherwise, the descriptor might briefly go out of
222
0
        // bounds.
223
0
        bv.set_len_unchecked(bitspan.len());
224
0
        bv.set_head(bitspan.head());
225
0
      })
226
0
  }
227
228
  /// Explicitly views the bit-box as a bit-slice.
229
  #[inline]
230
0
  pub fn as_bitslice(&self) -> &BitSlice<T, O> {
231
0
    unsafe { self.bitspan.into_bitslice_ref() }
232
0
  }
233
234
  /// Explicitly views the bit-box as a mutable bit-slice.
235
  #[inline]
236
0
  pub fn as_mut_bitslice(&mut self) -> &mut BitSlice<T, O> {
237
0
    unsafe { self.bitspan.into_bitslice_mut() }
238
0
  }
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
0
  pub fn as_raw_slice(&self) -> &[T] {
246
0
    let (data, len) =
247
0
      (self.bitspan.address().to_const(), self.bitspan.elements());
248
0
    unsafe { slice::from_raw_parts(data, len) }
249
0
  }
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
0
  pub fn as_raw_mut_slice(&mut self) -> &mut [T] {
257
0
    let (data, len) =
258
0
      (self.bitspan.address().to_mut(), self.bitspan.elements());
259
0
    unsafe { slice::from_raw_parts_mut(data, len) }
260
0
  }
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
0
  pub fn fill_uninitialized(&mut self, value: bool) {
295
0
    let (_, head, bits) = self.bitspan.raw_parts();
296
0
    let head = head.into_inner() as usize;
297
0
    let tail = head + bits;
298
0
    let all = self.as_raw_mut_slice().view_bits_mut::<O>();
299
0
    unsafe {
300
0
      all.get_unchecked_mut(.. head).fill(value);
301
0
      all.get_unchecked_mut(tail ..).fill(value);
302
0
    }
303
0
  }
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
0
  pub fn force_align(&mut self) {
339
0
    let head = self.bitspan.head();
340
0
    if head == BitIdx::MIN {
341
0
      return;
342
0
    }
343
0
    let head = head.into_inner() as usize;
344
0
    let last = self.len() + head;
345
0
    unsafe {
346
0
      self.bitspan.set_head(BitIdx::MIN);
347
0
      self.copy_within_unchecked(head .. last, 0);
348
0
    }
349
0
  }
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
0
  fn with_box<F, R>(&mut self, func: F) -> R
359
0
  where F: FnOnce(&mut ManuallyDrop<Box<[T]>>) -> R {
360
0
    self.as_raw_mut_slice()
361
0
      .pipe(|raw| unsafe { Box::from_raw(raw) })
362
0
      .pipe(ManuallyDrop::new)
363
0
      .pipe_ref_mut(func)
364
0
  }
365
}