use core::convert::TryFrom;
use core::fmt;
use core::marker::PhantomData;
use crate::bitfield::BitFieldTrait;
pub trait BitFieldAccess : private::Sealed
{
fn get_bitfield(&self, mask: Self, shift: u32) -> Self;
fn set_bitfield(&mut self, mask: Self, shift: u32, value: Self);
}
mod private {
pub trait Sealed {}
impl Sealed for u8 { }
impl Sealed for u16 { }
impl Sealed for u32 { }
impl Sealed for u64 { }
impl Sealed for usize { }
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
pub struct Storage<TMarker, TData>
where TData: BitFieldAccess
{
data: TData,
owner: PhantomData<TMarker>
}
macro_rules! impl_storage {
($type:ident) => {
impl<TMarker> Storage<TMarker, $type>
{
pub fn new() -> Self {
Storage {
data: $type::default(),
owner: PhantomData,
}
}
pub fn get<TBitField>(&self) -> $type
where
TBitField: BitFieldTrait<Owner=Self>
{
self.data.get_bitfield(TBitField::MASK as $type, TBitField::SHIFT)
}
pub fn set<TBitField>(&mut self, value: $type)
where
TBitField: BitFieldTrait<Owner=Self>
{
self.data.set_bitfield(TBitField::MASK as $type, TBitField::SHIFT, value);
}
}
impl BitFieldAccess for $type {
fn get_bitfield(&self, mask: Self, shift: u32) -> Self {
(self & mask as $type).wrapping_shr(shift)
}
fn set_bitfield(&mut self, mask: Self, shift: u32, field: Self) {
*self = *self & !mask as $type | (field.wrapping_shl(shift) & mask as $type);
}
}
impl<TMarker> fmt::Display for Storage<TMarker, $type>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.data)
}
}
impl<TMarker> fmt::UpperHex for Storage<TMarker, $type>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(&self, f)
}
}
impl<TMarker> fmt::LowerHex for Storage<TMarker, $type>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(&self, f)
}
}
impl<TMarker> fmt::Octal for Storage<TMarker, $type>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Octal::fmt(&self, f)
}
}
impl<TMarker> fmt::Binary for Storage<TMarker, $type>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Binary::fmt(&self, f)
}
}
};
}
macro_rules! impl_from {
($type:ident, $from:ident) => {
impl<TMarker> From<$from> for Storage<TMarker, $type>
{
fn from(value: $from) -> Self {
Self {
data: value.into(),
owner: PhantomData,
}
}
}
};
}
macro_rules! impl_tryfrom {
($type:ident, $from:ident) => {
impl<TMarker> TryFrom<$from> for Storage<TMarker, $type>
{
type Error = <$type as TryFrom<$from>>::Error;
fn try_from(value: $from) -> Result<Self, <$type as TryFrom<$from>>::Error> {
Ok(Self {
data: $type::try_from(value)?,
owner: PhantomData,
})
}
}
};
}
impl_storage!(u8);
impl_from!(u8, u8);
impl_tryfrom!(u8, u16);
impl_tryfrom!(u8, u32);
impl_tryfrom!(u8, u64);
impl_tryfrom!(u8, usize);
impl_storage!(u16);
impl_from!(u16, u8);
impl_from!(u16, u16);
impl_tryfrom!(u16, u32);
impl_tryfrom!(u16, u64);
impl_tryfrom!(u16, usize);
impl_storage!(u32);
impl_from!(u32, u8);
impl_from!(u32, u16);
impl_from!(u32, u32);
impl_tryfrom!(u32, u64);
impl_tryfrom!(u32, usize);
impl_storage!(u64);
impl_from!(u64, u8);
impl_from!(u64, u16);
impl_from!(u64, u32);
impl_from!(u64, u64);
impl_tryfrom!(u64, usize);
impl_storage!(usize);
impl_from!(usize, u8);
impl_from!(usize, u16);
impl_tryfrom!(usize, u32);
impl_tryfrom!(usize, u64);
impl_from!(usize, usize);
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_send() {
struct Marker;
fn assert_send<T: Send>() {}
assert_send::<Storage<Marker, u8>>();
assert_send::<Storage<Marker, u16>>();
assert_send::<Storage<Marker, u32>>();
assert_send::<Storage<Marker, u64>>();
assert_send::<Storage<Marker, usize>>();
}
#[test]
fn test_sync() {
struct Marker;
fn assert_sync<T: Sync>() {}
assert_sync::<Storage<Marker, u8>>();
assert_sync::<Storage<Marker, u16>>();
assert_sync::<Storage<Marker, u32>>();
assert_sync::<Storage<Marker, u64>>();
assert_sync::<Storage<Marker, usize>>();
}
}