1 /*! View constructors for memory regions.
2 
3 The `&BitSlice` type is a referential view over existing memory. The inherent
4 constructors are awkward to call, as they require function syntax rather than
5 method syntax, and must provide a token for the memory type even though this is
6 provided by the prior binding.
7 
8 This module provides a view trait, `ViewBits`, which provides `BitSlice`
9 constructors available in method-call syntax with only ordering type parameters.
10 
11 In addition, the traits `AsBits` and `AsBitsMut` are analogues of [`AsRef`] and
12 [`AsMut`], respectively. These traits have a blanket implementation for all
13 `A: As{Ref,Mut}<[T: BitStore]>`, so that any type that implements a view to a
14 suitable memory region automatically implements a view to that region’s bits.
15 
16 These traits are distinct because `ViewBits` combines the im/mutable view
17 functions into one trait, and can provide specialized implementations with a
18 slight performance increase over the generic, but `AsBits{,Mut}` can fit in the
19 generic type system of any library without undue effort.
20 
21 [`AsMut`]: https://doc.rust-lang.org/core/convert/trait.AsMut.html
22 [`AsRef`]: https://doc.rust-lang.org/core/convert/trait.AsRef.html
23 !*/
24 
25 use crate::{
26 	index::{
27 		BitIdx,
28 		BitRegister,
29 	},
30 	mem::BitMemory,
31 	order::BitOrder,
32 	pointer::BitPtr,
33 	slice::BitSlice,
34 	store::BitStore,
35 };
36 
37 /** Views a type that can store bits as a bit-slice.
38 
39 This trait is implemented on all `T: BitStore` types, and the arrays and slices
40 of them that are supported by the standard library.
41 
42 This means that until type-level integers are stabilized, only arrays in
43 `[T: BitStore; 0 ..= 32]` will implement the trait; wider arrays will need to
44 reborrow as slices `[T]` in order to use the slice implementation.
45 
46 If you have a type that contains a bit-storage type that can be viewed with this
47 trait, then you can implement this trait by forwarding to the interior view.
48 **/
49 pub trait BitView {
50 	/// The access-control type of the storage region.
51 	type Store: BitStore;
52 
53 	/// The underlying register type of the storage region.
54 	type Mem: BitMemory;
55 
56 	/// Views a memory region as a `BitSlice`.
57 	///
58 	/// # Type Parameters
59 	///
60 	/// - `O`: The bit ordering used for the region.
61 	///
62 	/// # Parameters
63 	///
64 	/// - `&self`: The region to view as individual bits.
65 	///
66 	/// # Returns
67 	///
68 	/// A `&BitSlice` view over the region at `*self`.
view_bits<O>(&self) -> &BitSlice<O, Self::Store> where O: BitOrder69 	fn view_bits<O>(&self) -> &BitSlice<O, Self::Store>
70 	where O: BitOrder;
71 
72 	#[doc(hidden)]
73 	#[inline(always)]
74 	#[cfg(not(tarpaulin_include))]
75 	#[deprecated(
76 		since = "0.18.0",
77 		note = "The method is renamed to `.view_bits`"
78 	)]
bits<O>(&self) -> &BitSlice<O, Self::Store> where O: BitOrder79 	fn bits<O>(&self) -> &BitSlice<O, Self::Store>
80 	where O: BitOrder {
81 		self.view_bits::<O>()
82 	}
83 
84 	/// Views a memory region as a mutable `BitSlice`.
85 	///
86 	/// # Type Parameters
87 	///
88 	/// - `O`: The bit ordering used for the region.
89 	///
90 	/// # Parameters
91 	///
92 	/// - `&self`: The region to view as individual mutable bits.
93 	///
94 	/// # Returns
95 	///
96 	/// A `&mut BitSlice` view over the region at `*self`.
view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store> where O: BitOrder97 	fn view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store>
98 	where O: BitOrder;
99 
100 	#[doc(hidden)]
101 	#[inline(always)]
102 	#[cfg(not(tarpaulin_include))]
103 	#[deprecated(
104 		since = "0.18.0",
105 		note = "The method is renamed to `.view_bits_mut`"
106 	)]
bits_mut<O>(&mut self) -> &BitSlice<O, Self::Store> where O: BitOrder107 	fn bits_mut<O>(&mut self) -> &BitSlice<O, Self::Store>
108 	where O: BitOrder {
109 		self.view_bits_mut::<O>()
110 	}
111 
112 	/// Produces the number of bits that the implementing type can hold.
113 	#[doc(hidden)]
const_bits() -> usize where Self: Sized114 	fn const_bits() -> usize
115 	where Self: Sized {
116 		Self::const_elts() << <<Self::Store as BitStore>::Mem as BitMemory>::INDX
117 	}
118 
119 	/// Produces the number of memory elements that the implementing type holds.
120 	#[doc(hidden)]
const_elts() -> usize where Self: Sized121 	fn const_elts() -> usize
122 	where Self: Sized;
123 }
124 
125 #[cfg(not(tarpaulin_include))]
126 impl<T> BitView for T
127 where T: BitStore + BitRegister
128 {
129 	type Mem = T::Mem;
130 	type Store = Self;
131 
132 	#[inline(always)]
view_bits<O>(&self) -> &BitSlice<O, Self::Store> where O: BitOrder133 	fn view_bits<O>(&self) -> &BitSlice<O, Self::Store>
134 	where O: BitOrder {
135 		BitSlice::from_element(self)
136 	}
137 
138 	#[inline(always)]
view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store> where O: BitOrder139 	fn view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store>
140 	where O: BitOrder {
141 		BitSlice::from_element_mut(self)
142 	}
143 
144 	#[doc(hidden)]
145 	#[inline(always)]
const_elts() -> usize146 	fn const_elts() -> usize {
147 		1
148 	}
149 }
150 
151 #[cfg(not(tarpaulin_include))]
152 impl<T> BitView for [T]
153 where T: BitStore + BitRegister
154 {
155 	type Mem = T::Mem;
156 	type Store = T;
157 
158 	#[inline]
view_bits<O>(&self) -> &BitSlice<O, Self::Store> where O: BitOrder159 	fn view_bits<O>(&self) -> &BitSlice<O, Self::Store>
160 	where O: BitOrder {
161 		BitSlice::from_slice(self).expect("slice was too long to view as bits")
162 	}
163 
164 	#[inline]
view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store> where O: BitOrder165 	fn view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store>
166 	where O: BitOrder {
167 		BitSlice::from_slice_mut(self)
168 			.expect("slice was too long to view as bits")
169 	}
170 
171 	/// Slices cannot implement this function.
172 	#[cold]
173 	#[doc(hidden)]
174 	#[inline(never)]
const_elts() -> usize175 	fn const_elts() -> usize {
176 		unreachable!("This cannot be called on unsized slices")
177 	}
178 }
179 
180 #[cfg(not(tarpaulin_include))]
181 impl<T> BitView for [T; 0]
182 where T: BitStore
183 {
184 	type Mem = T::Mem;
185 	type Store = T;
186 
187 	#[inline(always)]
view_bits<O>(&self) -> &BitSlice<O, Self::Store> where O: BitOrder188 	fn view_bits<O>(&self) -> &BitSlice<O, Self::Store>
189 	where O: BitOrder {
190 		BitSlice::empty()
191 	}
192 
193 	#[inline(always)]
view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store> where O: BitOrder194 	fn view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store>
195 	where O: BitOrder {
196 		BitSlice::empty_mut()
197 	}
198 
199 	#[doc(hidden)]
200 	#[inline(always)]
const_elts() -> usize201 	fn const_elts() -> usize {
202 		0
203 	}
204 }
205 
206 //  Replace with a const-generic once that becomes available.
207 macro_rules! view_bits {
208 	($($n:expr),+ $(,)?) => { $(
209 		#[cfg(not(tarpaulin_include))]
210 		impl<T> BitView for [T; $n]
211 		where T: BitStore {
212 			type Store = T;
213 			type Mem = T::Mem;
214 
215 			#[inline]
216 			fn view_bits<O>(&self) -> &BitSlice<O, Self::Store>
217 			where O: BitOrder {
218 				unsafe {
219 					BitPtr::new_unchecked(
220 						self.as_ptr(),
221 						BitIdx::ZERO,
222 						$n * T::Mem::BITS as usize,
223 					)
224 				}
225 				.to_bitslice_ref()
226 			}
227 
228 			#[inline]
229 			fn view_bits_mut<O>(&mut self) -> &mut BitSlice<O, Self::Store>
230 			where O: BitOrder {
231 				unsafe {
232 					BitPtr::new_unchecked(
233 						self.as_mut_ptr(),
234 						BitIdx::ZERO,
235 						$n * T::Mem::BITS as usize,
236 					)
237 				}
238 				.to_bitslice_mut()
239 			}
240 
241 			#[doc(hidden)]
242 			#[inline(always)]
243 			fn const_elts() -> usize {
244 				$n
245 			}
246 		}
247 	)+ };
248 }
249 
250 view_bits!(
251 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
252 	22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
253 	41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
254 	60, 61, 62, 63, 64
255 );
256 
257 /** Views a region as an immutable bit-slice only.
258 
259 This trait is an analogue to the [`AsRef`] trait, in that it enables any type to
260 provide an immutable-only view of a bit slice.
261 
262 It does not require an `AsRef<[T: BitStore]>` implementation, and a blanket
263 implementation for all such types is provided. This allows you to choose whether
264 to implement only one of `AsBits<T>` or `AsRef<[T]>`, and gain a bit-slice view
265 with either choice.
266 
267 # Type Parameters
268 
269 - `T`: The underlying storage region.
270 
271 # Notes
272 
273 You are not *forbidden* from creating multiple views with different element
274 types to the same region, but doing so is likely to cause inconsistent and
275 unsurprising behavior.
276 
277 Refrain from implementing this trait with more than one storage argument unless
278 you are sure that you can uphold the memory region requirements of all of them,
279 and are aware of the behavior conflicts that may arise.
280 
281 [`AsRef`]: https://doc.rust-lang.org/core/convert/trait.AsRef.html
282 **/
283 pub trait AsBits<T>
284 where T: BitStore
285 {
286 	/// Views memory as a slice of immutable bits.
287 	///
288 	/// # Type Parameters
289 	///
290 	/// - `O`: The bit ordering used for the region.
291 	///
292 	/// # Parameters
293 	///
294 	/// - `&self`: The value that is providing a bit-slice view.
295 	///
296 	/// # Returns
297 	///
298 	/// An immutable view into some bits.
as_bits<O>(&self) -> &BitSlice<O, T> where O: BitOrder299 	fn as_bits<O>(&self) -> &BitSlice<O, T>
300 	where O: BitOrder;
301 }
302 
303 /** Views a region as a mutable bit-slice.
304 
305 This trait is an analogue to the [`AsMut`] trait, in that it enables any type to
306 provide a mutable view of a bit slice.
307 
308 It does not require an `AsMut<[T: BitStore]>` implementation, and a blanket
309 implementation for all such types is provided. This allows you to choose whether
310 to implement only one of `AsBitsMut<T>` or `AsMut<[T]>`, and gain a bit-slice
311 view with either choice.
312 
313 # Type Parameters
314 
315 - `T`: The underlying storage region.
316 
317 # Notes
318 
319 You are not *forbidden* from creating multiple views with different element
320 types to the same region, but doing so is likely to cause inconsistent and
321 unsurprising behavior.
322 
323 Refrain from implementing this trait with more than one storage argument unless
324 you are sure that you can uphold the memory region requirements of all of them,
325 and are aware of the behavior conflicts that may arise.
326 
327 [`AsMut`]: https://doc.rust-lang.org/core/convert/trait.AsMut.html
328 **/
329 pub trait AsBitsMut<T>
330 where T: BitStore
331 {
332 	/// Views memory as a slice of mutable bits.
333 	///
334 	/// # Type Parameters
335 	///
336 	/// - `O`: The bit ordering used for the region.
337 	///
338 	/// # Parameters
339 	///
340 	/// - `&mut self`: The value that is providing a bit-slice view.
341 	///
342 	/// # Returns
343 	///
344 	/// A mutable view into some bits.
as_bits_mut<O>(&mut self) -> &mut BitSlice<O, T> where O: BitOrder345 	fn as_bits_mut<O>(&mut self) -> &mut BitSlice<O, T>
346 	where O: BitOrder;
347 }
348 
349 #[cfg(not(tarpaulin_include))]
350 impl<A, T> AsBits<T> for A
351 where
352 	A: AsRef<[T]>,
353 	T: BitStore + BitRegister,
354 {
355 	#[inline]
as_bits<O>(&self) -> &BitSlice<O, T> where O: BitOrder356 	fn as_bits<O>(&self) -> &BitSlice<O, T>
357 	where O: BitOrder {
358 		self.as_ref().view_bits::<O>()
359 	}
360 }
361 
362 #[cfg(not(tarpaulin_include))]
363 impl<A, T> AsBitsMut<T> for A
364 where
365 	A: AsMut<[T]>,
366 	T: BitStore + BitRegister,
367 {
368 	#[inline]
as_bits_mut<O>(&mut self) -> &mut BitSlice<O, T> where O: BitOrder369 	fn as_bits_mut<O>(&mut self) -> &mut BitSlice<O, T>
370 	where O: BitOrder {
371 		self.as_mut().view_bits_mut::<O>()
372 	}
373 }
374