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