1#![doc = include_str!("../doc/mem.md")]
2
3use core::{
4 cell::Cell,
5 mem,
6};
7
8use funty::Unsigned;
9use radium::marker::BitOps;
10
11#[doc = include_str!("../doc/mem/BitRegister.md")]
12pub trait BitRegister: Unsigned + BitOps {
13 const INDX: u8 = bits_of::<Self>().trailing_zeros() as u8;
15 const MASK: u8 = bits_of::<Self>() as u8 - 1;
18 const ALL: Self;
20}
21
22macro_rules! register {
24 ($($t:ty),+ $(,)?) => { $(
25 impl BitRegister for $t {
26 const ALL: Self = !0;
27 }
28 )+ };
29}
30
31register!(u8, u16, u32);
32
33#[cfg(target_pointer_width = "64")]
39impl BitRegister for u64 {
40 const ALL: Self = !0;
41}
42
43register!(usize);
44
45pub const fn bits_of<T>() -> usize {
47 core::mem::size_of::<T>().saturating_mul(<u8>::BITS as usize)
48}
49
50#[doc = include_str!("../doc/mem/elts.md")]
51pub const fn elts<T>(bits: usize) -> usize {
52 let width = bits_of::<T>();
53 if width == 0 {
54 return 0;
55 }
56 bits / width + (bits % width != 0) as usize
57}
58
59#[doc(hidden)]
61#[cfg(not(tarpaulin_include))]
62pub const fn aligned_to_size<T>() -> bool {
63 mem::align_of::<T>() == mem::size_of::<T>()
64}
65
66#[doc(hidden)]
68#[cfg(not(tarpaulin_include))]
69pub const fn layout_eq<T, U>() -> bool {
70 mem::align_of::<T>() == mem::align_of::<U>()
71 && mem::size_of::<T>() == mem::size_of::<U>()
72}
73
74#[doc(hidden)]
75#[repr(transparent)]
76#[doc = include_str!("../doc/mem/BitElement.md")]
77#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
78pub struct BitElement<T = usize> {
79 pub elem: T,
80}
81
82macro_rules! element {
85 ($($size:tt, $bare:ty => $atom:ident);+ $(;)?) => { $(
86 impl BitElement<$bare> {
87 pub const fn new(elem: $bare) -> Self {
89 Self {
90 elem,
91 }
92 }
93 }
94
95 impl BitElement<Cell<$bare>> {
96 pub const fn new(elem: $bare) -> Self {
98 Self {
99 elem: Cell::new(elem),
100 }
101 }
102 }
103
104 radium::if_atomic!( if atomic($size) {
105 use core::sync::atomic::$atom;
106 impl BitElement<$atom> {
107 pub const fn new(elem: $bare) -> Self {
109 Self {
110 elem: <$atom>::new(elem),
111 }
112 }
113 }
114 });
115 )+ };
116}
117
118element! {
119 8, u8 => AtomicU8;
120 16, u16 => AtomicU16;
121 32, u32 => AtomicU32;
122}
123
124#[cfg(target_pointer_width = "64")]
125element!(64, u64 => AtomicU64);
126
127element!(size, usize => AtomicUsize);
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use crate::access::*;
133
134 #[test]
135 fn integer_properties() {
136 assert!(aligned_to_size::<u8>());
137 assert!(aligned_to_size::<BitSafeU8>());
138 assert!(layout_eq::<u8, BitSafeU8>());
139
140 assert!(aligned_to_size::<u16>());
141 assert!(aligned_to_size::<BitSafeU16>());
142 assert!(layout_eq::<u16, BitSafeU16>());
143
144 assert!(aligned_to_size::<u32>());
145 assert!(aligned_to_size::<BitSafeU32>());
146 assert!(layout_eq::<u32, BitSafeU32>());
147
148 assert!(aligned_to_size::<usize>());
149 assert!(aligned_to_size::<BitSafeUsize>());
150 assert!(layout_eq::<usize, BitSafeUsize>());
151
152 #[cfg(target_pointer_width = "64")]
153 {
154 assert!(aligned_to_size::<u64>());
155 assert!(aligned_to_size::<BitSafeU64>());
156 assert!(layout_eq::<u64, BitSafeU64>());
157 }
158 }
159}