#![doc = include_str!("../doc/mem.md")]
use core::{
cell::Cell,
mem,
};
use funty::Unsigned;
use radium::marker::BitOps;
#[doc = include_str!("../doc/mem/BitRegister.md")]
pub trait BitRegister: Unsigned + BitOps {
const INDX: u8 = bits_of::<Self>().trailing_zeros() as u8;
const MASK: u8 = bits_of::<Self>() as u8 - 1;
const ALL: Self;
}
macro_rules! register {
($($t:ty),+ $(,)?) => { $(
impl BitRegister for $t {
const ALL: Self = !0;
}
)+ };
}
register!(u8, u16, u32);
#[cfg(target_pointer_width = "64")]
impl BitRegister for u64 {
const ALL: Self = !0;
}
register!(usize);
pub const fn bits_of<T>() -> usize {
core::mem::size_of::<T>().saturating_mul(<u8>::BITS as usize)
}
#[doc = include_str!("../doc/mem/elts.md")]
pub const fn elts<T>(bits: usize) -> usize {
let width = bits_of::<T>();
if width == 0 {
return 0;
}
bits / width + (bits % width != 0) as usize
}
#[doc(hidden)]
#[cfg(not(tarpaulin_include))]
pub const fn aligned_to_size<T>() -> bool {
mem::align_of::<T>() == mem::size_of::<T>()
}
#[doc(hidden)]
#[cfg(not(tarpaulin_include))]
pub const fn layout_eq<T, U>() -> bool {
mem::align_of::<T>() == mem::align_of::<U>()
&& mem::size_of::<T>() == mem::size_of::<U>()
}
#[doc(hidden)]
#[repr(transparent)]
#[doc = include_str!("../doc/mem/BitElement.md")]
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BitElement<T = usize> {
pub elem: T,
}
macro_rules! element {
($($size:tt, $bare:ty => $atom:ident);+ $(;)?) => { $(
impl BitElement<$bare> {
pub const fn new(elem: $bare) -> Self {
Self {
elem,
}
}
}
impl BitElement<Cell<$bare>> {
pub const fn new(elem: $bare) -> Self {
Self {
elem: Cell::new(elem),
}
}
}
radium::if_atomic!( if atomic($size) {
use core::sync::atomic::$atom;
impl BitElement<$atom> {
pub const fn new(elem: $bare) -> Self {
Self {
elem: <$atom>::new(elem),
}
}
}
});
)+ };
}
element! {
8, u8 => AtomicU8;
16, u16 => AtomicU16;
32, u32 => AtomicU32;
}
#[cfg(target_pointer_width = "64")]
element!(64, u64 => AtomicU64);
element!(size, usize => AtomicUsize);
#[cfg(test)]
mod tests {
use super::*;
use crate::access::*;
#[test]
fn integer_properties() {
assert!(aligned_to_size::<u8>());
assert!(aligned_to_size::<BitSafeU8>());
assert!(layout_eq::<u8, BitSafeU8>());
assert!(aligned_to_size::<u16>());
assert!(aligned_to_size::<BitSafeU16>());
assert!(layout_eq::<u16, BitSafeU16>());
assert!(aligned_to_size::<u32>());
assert!(aligned_to_size::<BitSafeU32>());
assert!(layout_eq::<u32, BitSafeU32>());
assert!(aligned_to_size::<usize>());
assert!(aligned_to_size::<BitSafeUsize>());
assert!(layout_eq::<usize, BitSafeUsize>());
#[cfg(target_pointer_width = "64")]
{
assert!(aligned_to_size::<u64>());
assert!(aligned_to_size::<BitSafeU64>());
assert!(layout_eq::<u64, BitSafeU64>());
}
}
}