Coverage Report

Created: 2025-07-18 06:16

/rust/registry/src/index.crates.io-6f17d22bba15001f/bitvec-1.0.1/src/access.rs
Line
Count
Source (jump to first uncovered line)
1
#![doc = include_str!("../doc/access.md")]
2
3
use core::sync::atomic::Ordering;
4
5
use funty::Integral;
6
use radium::Radium;
7
8
use crate::{
9
  index::{
10
    BitIdx,
11
    BitMask,
12
  },
13
  mem::BitRegister,
14
  order::BitOrder,
15
};
16
17
#[doc = include_str!("../doc/access/BitAccess.md")]
18
pub trait BitAccess: Radium
19
where <Self as Radium>::Item: BitRegister
20
{
21
  /// Clears bits within a memory element to `0`.
22
  ///
23
  /// The mask provided to this method must be constructed from indices that
24
  /// are valid in the caller’s context. As the mask is already computed by
25
  /// the caller, this does not take an ordering type parameter.
26
  ///
27
  /// ## Parameters
28
  ///
29
  /// - `mask`: A mask of any number of bits. This is a selection mask: all
30
  ///   bits in the mask that are set to `1` will set the corresponding bit in
31
  ///   `*self` to `0`.
32
  ///
33
  /// ## Returns
34
  ///
35
  /// The prior value of the memory element.
36
  ///
37
  /// ## Effects
38
  ///
39
  /// All bits in `*self` corresponding to `1` bits in the `mask` are cleared
40
  /// to `0`; all others retain their original value.
41
  ///
42
  /// Do not invert the `mask` prior to calling this function. [`BitMask`] is
43
  /// a selection type, not a bitwise-operation argument.
44
  ///
45
  /// [`BitMask`]: crate::index::BitMask
46
  #[inline]
47
180k
  fn clear_bits(&self, mask: BitMask<Self::Item>) -> Self::Item {
48
180k
    self.fetch_and(!mask.into_inner(), Ordering::Relaxed)
49
180k
  }
<core::cell::Cell<u8> as bitvec::access::BitAccess>::clear_bits
Line
Count
Source
47
180k
  fn clear_bits(&self, mask: BitMask<Self::Item>) -> Self::Item {
48
180k
    self.fetch_and(!mask.into_inner(), Ordering::Relaxed)
49
180k
  }
Unexecuted instantiation: <_ as bitvec::access::BitAccess>::clear_bits
50
51
  /// Sets bits within a memory element to `1`.
52
  ///
53
  /// The mask provided to this method must be constructed from indices that
54
  /// are valid in the caller’s context. As the mask is already computed by
55
  /// the caller, this does not take an ordering type parameter.
56
  ///
57
  /// ## Parameters
58
  ///
59
  /// - `mask`: A mask of any number of bits. This is a selection mask: all
60
  ///   bits in the mask that are set to `1` will set the corresponding bit in
61
  ///   `*self` to `1`.
62
  ///
63
  /// ## Returns
64
  ///
65
  /// The prior value of the memory element.
66
  ///
67
  /// ## Effects
68
  ///
69
  /// All bits in `*self` corresponding to `1` bits in the `mask` are set to
70
  /// `1`; all others retain their original value.
71
  #[inline]
72
180k
  fn set_bits(&self, mask: BitMask<Self::Item>) -> Self::Item {
73
180k
    self.fetch_or(mask.into_inner(), Ordering::Relaxed)
74
180k
  }
<core::cell::Cell<u8> as bitvec::access::BitAccess>::set_bits
Line
Count
Source
72
180k
  fn set_bits(&self, mask: BitMask<Self::Item>) -> Self::Item {
73
180k
    self.fetch_or(mask.into_inner(), Ordering::Relaxed)
74
180k
  }
Unexecuted instantiation: <_ as bitvec::access::BitAccess>::set_bits
75
76
  /// Inverts bits within a memory element.
77
  ///
78
  /// The mask provided to this method must be constructed from indices that
79
  /// are valid in the caller’s context. As the mask is already computed by
80
  /// the caller, this does not take an ordering type parameter.
81
  ///
82
  /// ## Parameters
83
  ///
84
  /// - `mask`: A mask of any number of bits. This is a selection mask: all
85
  ///   bits in the mask that are set to `1` will invert the corresponding bit
86
  ///   in `*self`.
87
  ///
88
  /// ## Returns
89
  ///
90
  /// The prior value of the memory element.
91
  ///
92
  /// ## Effects
93
  ///
94
  /// All bits in `*self` corresponding to `1` bits in the `mask` are
95
  /// inverted; all others retain their original value.
96
  #[inline]
97
0
  fn invert_bits(&self, mask: BitMask<Self::Item>) -> Self::Item {
98
0
    self.fetch_xor(mask.into_inner(), Ordering::Relaxed)
99
0
  }
100
101
  /// Writes a value to one bit in a memory element, returning the previous
102
  /// value.
103
  ///
104
  /// ## Type Parameters
105
  ///
106
  /// - `O`: An ordering of bits in a memory element that translates the
107
  ///   `index` into a real position.
108
  ///
109
  /// ## Parameters
110
  ///
111
  /// - `index`: The semantic index of the bit in `*self` to modify.
112
  /// - `value`: The new bit value to write into `*self` at the `index`.
113
  ///
114
  /// ## Returns
115
  ///
116
  /// The bit previously stored in `*self` at `index`. These operations are
117
  /// required to load the `*self` value from memory in order to operate, and
118
  /// so always have the prior value available for use. This can reduce
119
  /// spurious loads throughout the crate.
120
  ///
121
  /// ## Effects
122
  ///
123
  /// `*self` is updated with the bit at `index` set to `value`; all other
124
  /// bits remain unchanged.
125
  #[inline]
126
32.9k
  fn write_bit<O>(&self, index: BitIdx<Self::Item>, value: bool) -> bool
127
32.9k
  where O: BitOrder {
128
32.9k
    let select = index.select::<O>().into_inner();
129
32.9k
    select
130
32.9k
      & if value {
131
3.53k
        self.fetch_or(select, Ordering::Relaxed)
132
      }
133
      else {
134
29.4k
        self.fetch_and(!select, Ordering::Relaxed)
135
32.9k
      } != <Self::Item>::ZERO
136
32.9k
  }
<core::cell::Cell<u8> as bitvec::access::BitAccess>::write_bit::<bitvec::order::Msb0>
Line
Count
Source
126
32.9k
  fn write_bit<O>(&self, index: BitIdx<Self::Item>, value: bool) -> bool
127
32.9k
  where O: BitOrder {
128
32.9k
    let select = index.select::<O>().into_inner();
129
32.9k
    select
130
32.9k
      & if value {
131
3.53k
        self.fetch_or(select, Ordering::Relaxed)
132
      }
133
      else {
134
29.4k
        self.fetch_and(!select, Ordering::Relaxed)
135
32.9k
      } != <Self::Item>::ZERO
136
32.9k
  }
Unexecuted instantiation: <_ as bitvec::access::BitAccess>::write_bit::<_>
137
138
  /// Gets the function that will write `value` into all bits under a mask.
139
  ///
140
  /// This is useful for preparing bulk operations that all write the same
141
  /// data into memory, and only need to provide the shape of memory to write.
142
  ///
143
  /// ## Parameters
144
  ///
145
  /// - `value`: The bit that will be written by the returned function.
146
  ///
147
  /// ## Returns
148
  ///
149
  /// A function which writes `value` into memory at a given address and under
150
  /// a given mask. If `value` is `false`, then this produces [`clear_bits`];
151
  /// if it is `true`, then this produces [`set_bits`].
152
  ///
153
  /// [`clear_bits`]: Self::clear_bits
154
  /// [`set_bits`]: Self::set_bits
155
  #[inline]
156
0
  fn get_writers(
157
0
    value: bool,
158
0
  ) -> for<'a> fn(&'a Self, BitMask<Self::Item>) -> Self::Item {
159
0
    if value {
160
0
      Self::set_bits
161
    }
162
    else {
163
0
      Self::clear_bits
164
    }
165
0
  }
166
}
167
168
impl<A> BitAccess for A
169
where
170
  A: Radium,
171
  A::Item: BitRegister,
172
{
173
}
174
175
#[doc = include_str!("../doc/access/BitSafe.md")]
176
pub trait BitSafe {
177
  /// The element type being guarded against improper mutation.
178
  ///
179
  /// This is only present as an extra proof that the type graph has a
180
  /// consistent view of the underlying memory.
181
  type Mem: BitRegister;
182
183
  /// The memory-access type this guards.
184
  ///
185
  /// This is exposed as an associated type so that `BitStore` can name it
186
  /// without having to re-select it based on crate configuration.
187
  type Rad: Radium<Item = Self::Mem>;
188
189
  /// The zero constant.
190
  const ZERO: Self;
191
192
  /// Loads the value from memory, allowing for the possibility that other
193
  /// handles have write permissions to it.
194
  fn load(&self) -> Self::Mem;
195
}
196
197
/// Constructs a shared-mutable guard type that disallows mutation *through it*.
198
macro_rules! safe {
199
  ($($t:ident => $w:ident => $r:ty);+ $(;)?) => { $(
200
    #[derive(Debug)]
201
    #[repr(transparent)]
202
    #[doc = include_str!("../doc/access/impl_BitSafe.md")]
203
    pub struct $w {
204
      inner: <Self as BitSafe>::Rad,
205
    }
206
207
    impl $w {
208
      /// Allow construction of the safed value by forwarding to its
209
      /// interior constructor.
210
      ///
211
      /// This type is not public API, and general use has no reason to
212
      /// construct values of it directly. It is provided for convenience
213
      /// as a crate internal.
214
0
      pub(crate) const fn new(value: $t) -> Self {
215
0
        Self { inner: <<Self as BitSafe>::Rad>::new(value) }
216
0
      }
Unexecuted instantiation: <bitvec::access::BitSafeU8>::new
Unexecuted instantiation: <bitvec::access::BitSafeU16>::new
Unexecuted instantiation: <bitvec::access::BitSafeU32>::new
Unexecuted instantiation: <bitvec::access::BitSafeU64>::new
Unexecuted instantiation: <bitvec::access::BitSafeUsize>::new
217
    }
218
219
    impl BitSafe for $w {
220
      type Mem = $t;
221
222
      #[cfg(feature = "atomic")]
223
      type Rad = $r;
224
225
      #[cfg(not(feature = "atomic"))]
226
      type Rad = core::cell::Cell<$t>;
227
228
      const ZERO: Self = Self::new(0);
229
230
      #[inline]
231
0
      fn load(&self) -> Self::Mem {
232
0
        self.inner.load(Ordering::Relaxed)
233
0
      }
Unexecuted instantiation: <bitvec::access::BitSafeU8 as bitvec::access::BitSafe>::load
Unexecuted instantiation: <bitvec::access::BitSafeU16 as bitvec::access::BitSafe>::load
Unexecuted instantiation: <bitvec::access::BitSafeU32 as bitvec::access::BitSafe>::load
Unexecuted instantiation: <bitvec::access::BitSafeU64 as bitvec::access::BitSafe>::load
Unexecuted instantiation: <bitvec::access::BitSafeUsize as bitvec::access::BitSafe>::load
234
    }
235
  )+ };
236
}
237
238
safe! {
239
  u8 => BitSafeU8 => radium::types::RadiumU8;
240
  u16 => BitSafeU16 => radium::types::RadiumU16;
241
  u32 => BitSafeU32 => radium::types::RadiumU32;
242
}
243
244
#[cfg(target_pointer_width = "64")]
245
safe!(u64 => BitSafeU64 => radium::types::RadiumU64);
246
247
safe!(usize => BitSafeUsize => radium::types::RadiumUsize);
248
249
#[cfg(test)]
250
mod tests {
251
  use core::cell::Cell;
252
253
  use super::*;
254
  use crate::prelude::*;
255
256
  #[test]
257
  fn touch_memory() {
258
    let data = Cell::new(0u8);
259
    let accessor = &data;
260
    let aliased = unsafe { &*(&data as *const _ as *const BitSafeU8) };
261
262
    assert!(!BitAccess::write_bit::<Lsb0>(
263
      accessor,
264
      BitIdx::new(1).unwrap(),
265
      true
266
    ));
267
    assert_eq!(aliased.load(), 2);
268
    assert!(BitAccess::write_bit::<Lsb0>(
269
      accessor,
270
      BitIdx::new(1).unwrap(),
271
      false
272
    ));
273
    assert_eq!(aliased.load(), 0);
274
  }
275
276
  #[test]
277
  #[cfg(not(miri))]
278
  fn sanity_check_prefetch() {
279
    use core::cell::Cell;
280
    assert_eq!(
281
      <Cell<u8> as BitAccess>::get_writers(false) as *const (),
282
      <Cell<u8> as BitAccess>::clear_bits as *const ()
283
    );
284
285
    assert_eq!(
286
      <Cell<u8> as BitAccess>::get_writers(true) as *const (),
287
      <Cell<u8> as BitAccess>::set_bits as *const ()
288
    );
289
  }
290
}