Skip to content

Commit 056a12f

Browse files
committed
Introduce BitVec::{try_,}from_partial_vec
Add BitVec::from_partial_vec and BitVec::try_from_partial_vec methods which construct the bit vector from part of the underlying vector. This makes it easy to create a bit vector which doesn’t start at the first bit of the underlying memory.
1 parent 5fb8550 commit 056a12f

2 files changed

Lines changed: 109 additions & 15 deletions

File tree

src/ptr/single.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,7 @@ where
367367
/// departure from the subslice, *even within the original slice*, illegal.
368368
#[inline]
369369
pub fn from_mut_slice(slice: &mut [T]) -> Self {
370-
unsafe {
371-
Self::new_unchecked(slice.as_mut_ptr().into_address(), BitIdx::MIN)
372-
}
370+
Self::from_slice_with_index_mut(slice, BitIdx::MIN)
373371
}
374372

375373
/// Constructs a mutable `BitPtr` to the zeroth bit in the zeroth element of
@@ -381,8 +379,12 @@ where
381379
/// departure from the subslice, *even within the original slice*, illegal.
382380
#[inline]
383381
pub fn from_slice_mut(slice: &mut [T]) -> Self {
382+
Self::from_slice_with_index_mut(slice, BitIdx::MIN)
383+
}
384+
385+
pub(crate) fn from_slice_with_index_mut(slice: &mut [T], bit: BitIdx<T::Mem>) -> Self {
384386
unsafe {
385-
Self::new_unchecked(slice.as_mut_ptr().into_address(), BitIdx::MIN)
387+
Self::new_unchecked(slice.as_mut_ptr().into_address(), bit)
386388
}
387389
}
388390

src/vec.rs

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,8 @@ where
120120
#[inline]
121121
pub fn from_bitslice(slice: &BitSlice<T, O>) -> Self {
122122
let bitspan = slice.as_bitspan();
123-
124-
let mut vec = bitspan
125-
.elements()
126-
.pipe(Vec::with_capacity)
127-
.pipe(ManuallyDrop::new);
128-
vec.extend(slice.domain());
129-
123+
let vec = slice.domain().into_iter().collect::<Vec<_>>();
124+
let mut vec = ManuallyDrop::new(vec);
130125
let bitspan = unsafe {
131126
BitSpan::new_unchecked(
132127
vec.as_mut_ptr().cast::<T>().into_address(),
@@ -241,11 +236,108 @@ where
241236
/// It is not practical to allocate a vector that will fail this conversion.
242237
#[inline]
243238
pub fn try_from_vec(vec: Vec<T>) -> Result<Self, Vec<T>> {
244-
let mut vec = ManuallyDrop::new(vec);
245-
let capacity = vec.capacity();
239+
Self::try_from_partial_vec(vec, BitIdx::MIN, None)
240+
}
246241

247-
BitPtr::from_mut_slice(vec.as_mut_slice())
248-
.span(vec.len() * bits_of::<T::Mem>())
242+
/// Converts a regular vector in-place into a bit-vector covering parts
243+
/// of the elements.
244+
///
245+
/// The produced bit-vector spans `length` bits of the original vector
246+
/// starting at `head` bit of the first element. If `length` is `None`,
247+
/// spans bits starting at `head` bit of the first element until the end
248+
/// of the original vector.
249+
///
250+
/// ## Panics
251+
///
252+
/// This panics if the source vector is too long to view as a bit-slice,
253+
/// or if specified total length of the vector goes beyond provided
254+
/// bytes.
255+
///
256+
/// ## Examples
257+
///
258+
/// ```rust
259+
/// use bitvec::prelude::*;
260+
/// use bitvec::index::BitIdx;
261+
///
262+
/// let bv = BitVec::<_, Msb0>::from_partial_vec(
263+
/// vec![0u8, 1, 0x80],
264+
/// BitIdx::new(4).unwrap(),
265+
/// Some(18),
266+
/// );
267+
/// assert_eq!(bits![0, 0, 0, 0,
268+
/// 0, 0, 0, 0, 0, 0, 0, 1,
269+
/// 1, 0, 0, 0, 0, 0], bv);
270+
/// ```
271+
#[inline]
272+
pub fn from_partial_vec(
273+
vec: Vec<T>,
274+
head: crate::index::BitIdx<T::Mem>,
275+
length: Option<usize>,
276+
) -> Self {
277+
Self::try_from_partial_vec(vec, head, length)
278+
.expect("vector was too long to be converted into a `BitVec`")
279+
}
280+
281+
/// Attempts to converts a regular vector in-place into a bit-vector
282+
/// covering parts of the elements.
283+
///
284+
/// This fails if the source vector is too long to view as a bit-slice,
285+
/// or if specified total length of the vector goes beyond provided
286+
/// bytes.
287+
///
288+
/// On success, the produced bit-vector spans `length` bits of the
289+
/// original vector starting at `head` bit of the first element. If
290+
/// `length` is `None`, spans bits starting at `head` bit of the first
291+
/// element until the end of the original vector.
292+
///
293+
/// ## Examples
294+
///
295+
/// ```rust
296+
/// use bitvec::prelude::*;
297+
/// use bitvec::index::BitIdx;
298+
///
299+
/// let bv = BitVec::<_, Msb0>::try_from_partial_vec(
300+
/// vec![0u8, 1, 0x80],
301+
/// BitIdx::new(4).unwrap(),
302+
/// Some(18),
303+
/// ).unwrap();
304+
/// assert_eq!(bits![0, 0, 0, 0,
305+
/// 0, 0, 0, 0, 0, 0, 0, 1,
306+
/// 1, 0, 0, 0, 0, 0], bv);
307+
///
308+
/// let bv = BitVec::<_, Msb0>::try_from_partial_vec(
309+
/// vec![0u8, 1, 0x80],
310+
/// BitIdx::new(4).unwrap(),
311+
/// Some(24),
312+
/// );
313+
/// assert_eq!(None, bv.ok());
314+
/// ```
315+
#[inline]
316+
pub fn try_from_partial_vec(
317+
vec: Vec<T>,
318+
head: crate::index::BitIdx<T::Mem>,
319+
length: Option<usize>,
320+
) -> Result<Self, Vec<T>> {
321+
let start = usize::from(head.into_inner());
322+
let length = if let Some(len) = length {
323+
len.checked_add(start)
324+
.map(crate::mem::elts::<T>)
325+
.is_some_and(|elts| elts <= vec.len())
326+
.then_some(len)
327+
} else {
328+
vec.len()
329+
.checked_mul(bits_of::<T::Mem>())
330+
.and_then(|len| len.checked_sub(start))
331+
};
332+
let length = match length {
333+
None => return Err(vec),
334+
Some(length) => length,
335+
};
336+
337+
let capacity = vec.capacity();
338+
let mut vec = ManuallyDrop::new(vec);
339+
BitPtr::from_slice_with_index_mut(vec.as_mut_slice(), head)
340+
.span(length)
249341
.map(|bitspan| Self { bitspan, capacity })
250342
.map_err(|_| ManuallyDrop::into_inner(vec))
251343
}

0 commit comments

Comments
 (0)