1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
/*! Heavy bit reference. Regrettably, while producing a read reference to a bit inside a `BitSlice` is relatively easy to do, Rust’s rules make it impossible to produce a write reference to one. This is because references must be addresses that the holder can derefence without type consideration. Read references inspect the `BitSlice` data sequence, and then produce references to static `true` and `false` values as appropriate; the returned address does not need to be actually within the referent memory region. A write reference, however, is required to be the address of a `bool` within the `BitSlice`, which can have `0u8` or `1u8` written into it. This rule makes production of any `&mut bool` from any `&mut BitSlice` impossible. Instead, the `BitMut` structure serves as a heavy-weight referential object, that cannot be used in the `&mut` write reference system, as a good-enough substitute. !*/ use crate::{ access::BitAccess, indices::BitIdx, order::BitOrder, slice::BitSlice, store::BitStore, }; use core::{ marker::PhantomData, ops::{ Deref, DerefMut, }, ptr::NonNull, }; /** Proxy referential type, equivalent to `&mut bool`. This structure is three words wide, and cannot ever fit into the existing Rust language and library infrastructure in the way `&BitSlice` does. While `&mut` write references are themselves an affine type, with a guaranteed single point of destruction and no duplication, the language forbids writing finalization logic for them. This means that a custom reference type which implements `Deref` and `DerefMut` to a location within the canonical handle, and on `Drop` writes the `Deref` location into referent memory, is impossible. Short of that, a C++-style thick reference-like type is as close as Rust will allow. **/ pub struct BitMut<'a, O, T> where O: BitOrder, T: 'a + BitStore { /// Inform the compiler that this has an exclusive borrow of a `BitSlice` pub(super) _parent: PhantomData<&'a mut BitSlice<O, T>>, /// Typed pointer to the memory element containing the proxied bit. pub(super) data: NonNull<T::Access>, /// Index of the proxied bit inside the targeted memory element. pub(super) head: BitIdx<T>, /// A local cache for `Deref` usage. pub(super) bit: bool, } impl<O, T> Deref for BitMut<'_, O, T> where O: BitOrder, T: BitStore { type Target = bool; fn deref(&self) -> &Self::Target { &self.bit } } impl<O, T> DerefMut for BitMut<'_, O, T> where O: BitOrder, T: BitStore { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.bit } } impl<O, T> Drop for BitMut<'_, O, T> where O: BitOrder, T: BitStore { fn drop(&mut self) { unsafe { (*self.data.as_ptr()).set::<O>(self.head, self.bit) } } }