diff --git a/Cargo.toml b/Cargo.toml index 2bc16881..f68afee3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ keywords = [ license = "MIT" readme = "README.md" repository = "https://github.com/ferrilab/bitvec" -rust-version = "1.56" +rust-version = "1.71" [features] alloc = [ diff --git a/README.md b/README.md index dfe5ae1a..387cf56a 100644 --- a/README.md +++ b/README.md @@ -397,7 +397,7 @@ does, how it works, and how it can be useful to you. [downloads_img]: https://img.shields.io/crates/dv/bitvec.svg?style=for-the-badge "Crate downloads" [license_file]: https://github.com/ferrilab/bitvec/blob/main/LICENSE.txt "Project license" [license_img]: https://img.shields.io/crates/l/bitvec.svg?style=for-the-badge "License badge" -[msrv_img]: https://img.shields.io/badge/MSRV-1.56-f46623?style=for-the-badge&logo=rust "Minimum Supported Rust Version: 1.56" +[msrv_img]: https://img.shields.io/badge/MSRV-1.71-f46623?style=for-the-badge&logo=rust "Minimum Supported Rust Version: 1.71" [`BitArray`]: https://docs.rs/bitvec/latest/bitvec/array/struct.BitArray.html diff --git a/clippy.toml b/clippy.toml index f80f3f9f..36673721 100644 --- a/clippy.toml +++ b/clippy.toml @@ -6,6 +6,6 @@ # attributes set directly in the source code. # ######################################################################## -msrv = "1.56.0" +msrv = "1.71.0" single-char-binding-names-threshold = 8 too-many-arguments-threshold = 8 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c274b753..ad1a2d1e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -6,7 +6,7 @@ ######################################################################## [toolchain] -channel = "1.56.0" +channel = "1.71.0" profile = "default" components = [ "clippy", diff --git a/src/ptr/single.rs b/src/ptr/single.rs index f896c9ea..e5190682 100644 --- a/src/ptr/single.rs +++ b/src/ptr/single.rs @@ -367,9 +367,7 @@ where /// departure from the subslice, *even within the original slice*, illegal. #[inline] pub fn from_mut_slice(slice: &mut [T]) -> Self { - unsafe { - Self::new_unchecked(slice.as_mut_ptr().into_address(), BitIdx::MIN) - } + Self::from_slice_with_index_mut(slice, BitIdx::MIN) } /// Constructs a mutable `BitPtr` to the zeroth bit in the zeroth element of @@ -381,8 +379,14 @@ where /// departure from the subslice, *even within the original slice*, illegal. #[inline] pub fn from_slice_mut(slice: &mut [T]) -> Self { + Self::from_slice_with_index_mut(slice, BitIdx::MIN) + } + + /// Constructs a mutable `BitPtr` to the given bit in the zeroth element of + /// a slice. + pub(crate) fn from_slice_with_index_mut(slice: &mut [T], bit: BitIdx) -> Self { unsafe { - Self::new_unchecked(slice.as_mut_ptr().into_address(), BitIdx::MIN) + Self::new_unchecked(slice.as_mut_ptr().into_address(), bit) } } diff --git a/src/vec.rs b/src/vec.rs index ead0b436..466895a0 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -120,13 +120,8 @@ where #[inline] pub fn from_bitslice(slice: &BitSlice) -> Self { let bitspan = slice.as_bitspan(); - - let mut vec = bitspan - .elements() - .pipe(Vec::with_capacity) - .pipe(ManuallyDrop::new); - vec.extend(slice.domain()); - + let vec = slice.domain().into_iter().collect::>(); + let mut vec = ManuallyDrop::new(vec); let bitspan = unsafe { BitSpan::new_unchecked( vec.as_mut_ptr().cast::().into_address(), @@ -241,11 +236,108 @@ where /// It is not practical to allocate a vector that will fail this conversion. #[inline] pub fn try_from_vec(vec: Vec) -> Result> { - let mut vec = ManuallyDrop::new(vec); - let capacity = vec.capacity(); + Self::try_from_partial_vec(vec, BitIdx::MIN, None) + } - BitPtr::from_mut_slice(vec.as_mut_slice()) - .span(vec.len() * bits_of::()) + /// Converts a regular vector in-place into a bit-vector covering parts + /// of the elements. + /// + /// The produced bit-vector spans `length` bits of the original vector + /// starting at `head` bit of the first element. If `length` is `None`, + /// spans bits starting at `head` bit of the first element until the end + /// of the original vector. + /// + /// ## Panics + /// + /// This panics if the source vector is too long to view as a bit-slice, + /// or if specified total length of the vector goes beyond provided + /// bytes. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::index::BitIdx; + /// + /// let bv = BitVec::<_, Msb0>::from_partial_vec( + /// vec![0u8, 1, 0x80], + /// BitIdx::new(4).unwrap(), + /// Some(18), + /// ); + /// assert_eq!(bits![0, 0, 0, 0, + /// 0, 0, 0, 0, 0, 0, 0, 1, + /// 1, 0, 0, 0, 0, 0], bv); + /// ``` + #[inline] + pub fn from_partial_vec( + vec: Vec, + head: crate::index::BitIdx, + length: Option, + ) -> Self { + Self::try_from_partial_vec(vec, head, length) + .expect("vector was too long to be converted into a `BitVec`") + } + + /// Attempts to converts a regular vector in-place into a bit-vector + /// covering parts of the elements. + /// + /// This fails if the source vector is too long to view as a bit-slice, + /// or if specified total length of the vector goes beyond provided + /// bytes. + /// + /// On success, the produced bit-vector spans `length` bits of the + /// original vector starting at `head` bit of the first element. If + /// `length` is `None`, spans bits starting at `head` bit of the first + /// element until the end of the original vector. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::index::BitIdx; + /// + /// let bv = BitVec::<_, Msb0>::try_from_partial_vec( + /// vec![0u8, 1, 0x80], + /// BitIdx::new(4).unwrap(), + /// Some(18), + /// ).unwrap(); + /// assert_eq!(bits![0, 0, 0, 0, + /// 0, 0, 0, 0, 0, 0, 0, 1, + /// 1, 0, 0, 0, 0, 0], bv); + /// + /// let bv = BitVec::<_, Msb0>::try_from_partial_vec( + /// vec![0u8, 1, 0x80], + /// BitIdx::new(4).unwrap(), + /// Some(24), + /// ); + /// assert_eq!(None, bv.ok()); + /// ``` + #[inline] + pub fn try_from_partial_vec( + vec: Vec, + head: crate::index::BitIdx, + length: Option, + ) -> Result> { + let start = usize::from(head.into_inner()); + let length = if let Some(len) = length { + len.checked_add(start) + .map(crate::mem::elts::) + .is_some_and(|elts| elts <= vec.len()) + .then_some(len) + } else { + vec.len() + .checked_mul(bits_of::()) + .and_then(|len| len.checked_sub(start)) + }; + let length = match length { + None => return Err(vec), + Some(length) => length, + }; + + let capacity = vec.capacity(); + let mut vec = ManuallyDrop::new(vec); + BitPtr::from_slice_with_index_mut(vec.as_mut_slice(), head) + .span(length) .map(|bitspan| Self { bitspan, capacity }) .map_err(|_| ManuallyDrop::into_inner(vec)) }