1 /*! Utilities needed to develop `bitvec` itself.
2
3 This module contains required to perform generic programming in the `bitvec`
4 type system. These are not part of the SemVer public API, as they are only
5 required when interacting directly with the `bitvec` type system, and are not
6 needed to use its data structures directly.
7
8 This module is provided, under `feature = "devel"`, for the use of other crates
9 that wish to safely perform generic programming with `bitvec` region types.
10 !*/
11
12 #![allow(dead_code)]
13 #![cfg_attr(tarpaulin, skip)]
14
15 use crate::{
16 index::BitMask,
17 pointer::BitPtr,
18 store::BitStore,
19 };
20
21 use core::{
22 ops::{
23 Bound,
24 Range,
25 RangeBounds,
26 },
27 ptr::{
28 self,
29 NonNull,
30 },
31 };
32
33 use tap::pipe::Pipe;
34
35 /// Views a `BitStore` reference as its accessor.
36 #[inline(always)]
37 #[cfg(not(tarpaulin_include))]
accessor<T>(x: &T) -> &T::Access where T: BitStore38 pub fn accessor<T>(x: &T) -> &T::Access
39 where T: BitStore {
40 unsafe { &*(x as *const T as *const T::Access) }
41 }
42
43 /// Inserts an `::Alias` marker into a `BitMask`’s type parameter.
44 #[inline(always)]
45 #[cfg(not(tarpaulin_include))]
alias_mask<T>( x: BitMask<T::Mem>, ) -> BitMask<<T::Alias as BitStore>::Mem> where T: BitStore46 pub fn alias_mask<T>(
47 x: BitMask<T::Mem>,
48 ) -> BitMask<<T::Alias as BitStore>::Mem>
49 where T: BitStore {
50 unsafe { *(&x as *const _ as *const _) }
51 }
52
53 /// Inserts an `::Alias` marker into a `T::Mem` value’s type.
54 #[inline(always)]
55 #[cfg(not(tarpaulin_include))]
alias_mem<T>(x: T::Mem) -> <T::Alias as BitStore>::Mem where T: BitStore56 pub fn alias_mem<T>(x: T::Mem) -> <T::Alias as BitStore>::Mem
57 where T: BitStore {
58 unsafe { *(&x as *const _ as *const _) }
59 }
60
61 /// Loads through an aliased reference into an unmarked local.
62 #[inline(always)]
63 #[cfg(not(tarpaulin_include))]
load_aliased_local<T>(x: &T::Alias) -> T::Mem where T: BitStore64 pub fn load_aliased_local<T>(x: &T::Alias) -> T::Mem
65 where T: BitStore {
66 x.load_value().pipe(remove_alias::<T>)
67 }
68
69 /// Converts a mutable reference into its memory register type.
70 #[inline(always)]
71 #[cfg(not(tarpaulin_include))]
mem_mut<T>(x: &mut T) -> &mut T::Mem where T: BitStore72 pub fn mem_mut<T>(x: &mut T) -> &mut T::Mem
73 where T: BitStore {
74 unsafe { &mut *(x as *mut _ as *mut _) }
75 }
76
77 /// Removes the `::Alias` marker from a register value’s type.
78 #[inline(always)]
79 #[cfg(not(tarpaulin_include))]
remove_alias<T>(x: <<T as BitStore>::Alias as BitStore>::Mem) -> T::Mem where T: BitStore80 pub fn remove_alias<T>(x: <<T as BitStore>::Alias as BitStore>::Mem) -> T::Mem
81 where T: BitStore {
82 unsafe { *(&x as *const _ as *const _) }
83 }
84
85 /// Removes the `::Alias` marker from a `BitPtr`’s referent type.
86 #[inline(always)]
87 #[cfg(not(tarpaulin_include))]
remove_bitptr_alias<T>(x: BitPtr<T::Alias>) -> BitPtr<T> where T: BitStore88 pub fn remove_bitptr_alias<T>(x: BitPtr<T::Alias>) -> BitPtr<T>
89 where T: BitStore {
90 unsafe { *(&x as *const _ as *const _) }
91 }
92
93 /// Removes the `::Mem` marker from a memory value.
94 #[inline(always)]
95 #[cfg(not(tarpaulin_include))]
remove_mem<T>(x: T::Mem) -> T where T: BitStore96 pub fn remove_mem<T>(x: T::Mem) -> T
97 where T: BitStore {
98 unsafe { ptr::read(&x as *const T::Mem as *const T) }
99 }
100
101 /// Gets a `NonNull<T>` base pointer from a `NonNull<[T]>` slice pointer.
102 #[inline(always)]
103 #[cfg(not(tarpaulin_include))]
nonnull_slice_to_base<T>(mut nn_slice: NonNull<[T]>) -> NonNull<T>104 pub fn nonnull_slice_to_base<T>(mut nn_slice: NonNull<[T]>) -> NonNull<T> {
105 unsafe { nn_slice.as_mut() }
106 .pipe(<[T]>::as_mut_ptr)
107 .pipe(|p| unsafe { NonNull::new_unchecked(p) })
108 }
109
110 /** Normalizes any range into a basic `Range`.
111
112 This unpacks any range type into an ordinary `Range`, returning the start and
113 exclusive end markers. If the start marker is not provided, it is assumed to be
114 zero; if the end marker is not provided, then it is assumed to be `end`.
115
116 The end marker, if provided, may be greater than `end`. This is not checked in
117 the function, and must be inspected by the caller.
118
119 # Type Parameters
120
121 - `R`: A range of some kind
122
123 # Parameters
124
125 - `bounds`: A range of some kind
126 - `end`: The value to use as the exclusive end, if the range does not have an
127 end.
128
129 # Returns
130
131 `bounds` normalized to an ordinary `Range`, optionally clamped to `end`.
132 **/
133 #[inline]
normalize_range<R>(bounds: R, end: usize) -> Range<usize> where R: RangeBounds<usize>134 pub fn normalize_range<R>(bounds: R, end: usize) -> Range<usize>
135 where R: RangeBounds<usize> {
136 let min = match bounds.start_bound() {
137 Bound::Included(&n) => n,
138 Bound::Excluded(&n) => n + 1,
139 Bound::Unbounded => 0,
140 };
141 let max = match bounds.end_bound() {
142 Bound::Included(&n) => n + 1,
143 Bound::Excluded(&n) => n,
144 Bound::Unbounded => end,
145 };
146 min .. max
147 }
148
149 /** Asserts that a range satisfies bounds constraints.
150
151 This requires that the range start be not greater than the range end, and the
152 range end be not greater than the ending marker (if provided).
153
154 # Parameters
155
156 - `range`: The range to validate
157 - `end`: An optional maximal value that the range cannot exceed
158
159 # Panics
160
161 This panics if the range fails a requirement.
162 **/
163 #[inline]
assert_range(range: Range<usize>, end: impl Into<Option<usize>>)164 pub fn assert_range(range: Range<usize>, end: impl Into<Option<usize>>) {
165 if range.start > range.end {
166 panic!(
167 "Malformed range: `{} .. {}` must run from lower to higher",
168 range.start, range.end
169 );
170 }
171 if let Some(end) = end.into() {
172 if range.end > end {
173 panic!(
174 "Range out of bounds: `{} .. {}` must not exceed `{}`",
175 range.start, range.end, end
176 );
177 }
178 }
179 }
180
181 #[cfg(all(test, feature = "std"))]
182 mod tests {
183 use super::*;
184 use std::panic::catch_unwind;
185
186 #[test]
check_range_asserts()187 fn check_range_asserts() {
188 assert!(catch_unwind(|| assert_range(7 .. 2, None)).is_err());
189 assert!(catch_unwind(|| assert_range(0 .. 8, 4)).is_err());
190 }
191 }
192