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