use core::marker::PhantomData;
use core::ops::{Add, BitAnd, BitOr, Shl, Shr};
use typenum::consts::{True, U0};
use typenum::{IsGreater, IsGreaterOrEqual, IsLessOrEqual, Unsigned};
use super::bounds::{Bounded, ReifyTo};
pub struct ReadOnlyCopy<W, R>(pub W, pub PhantomData<R>);
impl<W, R> ReadOnlyCopy<W, R>
where
W: Copy + Clone + PartialOrd + BitAnd<W, Output = W> + Shr<W, Output = W> + Default,
{
pub fn get_field<M: Unsigned, O: Unsigned, U: Unsigned>(
&self,
f: Field<W, M, O, U, R>,
) -> Option<Field<W, M, O, U, R>>
where
U: IsGreater<U0, Output = True> + ReifyTo<W>,
M: ReifyTo<W>,
O: ReifyTo<W>,
U0: ReifyTo<W>,
{
f.set((self.0 & M::reify()) >> O::reify())
}
pub fn read(&self) -> W {
self.0
}
pub fn extract(&self) -> Self {
ReadOnlyCopy(self.0, PhantomData)
}
pub fn is_set<M: Unsigned, O: Unsigned, U: Unsigned>(&self, _: Field<W, M, O, U, R>) -> bool
where
U: IsGreater<U0, Output = True>,
U: ReifyTo<W>,
M: ReifyTo<W>,
O: ReifyTo<W>,
{
((self.0 & M::reify()) >> O::reify()) == U::reify()
}
pub fn matches_any<V: Positioned<Width = W>>(&self, val: V) -> bool {
(val.in_position() & self.0) != W::default()
}
pub fn matches_all<V: Positioned<Width = W>>(&self, val: V) -> bool {
(val.in_position() & self.0) == val.in_position()
}
}
#[derive(Debug)]
pub struct Field<W, M, O, U, R>
where
U: IsGreater<U0, Output = True>,
{
val: Bounded<W, U0, U>,
_mask: PhantomData<M>,
_offset: PhantomData<O>,
_reg_type: PhantomData<R>,
}
impl<W, M: Unsigned, O: Unsigned, U: Unsigned, R> Field<W, M, O, U, R>
where
U: IsGreater<U0, Output = True> + ReifyTo<W>,
W: Copy + Clone + PartialOrd + BitAnd<W, Output = W> + Shr<W, Output = W> + Default,
U: ReifyTo<W>,
U0: ReifyTo<W>,
{
pub fn new(val: W) -> Option<Self> {
Bounded::new(val).map(|val| Self {
val: val,
_offset: PhantomData,
_mask: PhantomData,
_reg_type: PhantomData,
})
}
pub fn set(mut self, val: W) -> Option<Self> {
Bounded::new(val).map(|val| {
self.val = val;
self
})
}
pub fn val(&self) -> W {
self.val.val
}
pub fn is_set(&self) -> bool {
self.val.val == U::reify()
}
}
macro_rules! checked {
($num_type:ty) => {
impl<M: Unsigned, O: Unsigned, U: Unsigned, R> Field<$num_type, M, O, U, R>
where
U: IsGreater<U0, Output = True>,
{
pub const fn checked<V: Unsigned>() -> Self
where
V: IsLessOrEqual<U, Output = True>,
V: IsGreaterOrEqual<U0, Output = True>,
{
Self {
val: Bounded::<$num_type, U0, U>::checked::<V>(),
_offset: PhantomData,
_mask: PhantomData,
_reg_type: PhantomData,
}
}
}
};
}
checked!(u8);
checked!(u16);
checked!(u32);
checked!(u64);
checked!(usize);
impl<W, M: Unsigned, O: Unsigned, U: Unsigned, R> PartialEq<Field<W, M, O, U, R>>
for Field<W, M, O, U, R>
where
U: IsGreater<U0, Output = True> + ReifyTo<W>,
W: Copy + Clone + PartialOrd + BitAnd<W, Output = W> + Shr<W, Output = W> + Default,
U0: ReifyTo<W>,
{
fn eq(&self, rhs: &Field<W, M, O, U, R>) -> bool {
self.val() == rhs.val()
}
}
pub trait Positioned {
type Width;
fn mask(&self) -> Self::Width;
fn in_position(&self) -> Self::Width;
}
impl<W, M: Unsigned, O: Unsigned, U: Unsigned, R> Positioned for Field<W, M, O, U, R>
where
U: IsGreater<U0, Output = True> + ReifyTo<W>,
W: Copy
+ Clone
+ PartialOrd
+ BitAnd<W, Output = W>
+ Shr<W, Output = W>
+ Default
+ Shl<W, Output = W>,
M: ReifyTo<W>,
U0: ReifyTo<W>,
O: ReifyTo<W>,
{
type Width = W;
fn mask(&self) -> W {
M::reify()
}
fn in_position(&self) -> W {
self.val() << O::reify()
}
}
pub struct FieldDisj<W> {
mask: W,
val: W,
}
impl<W: Copy> Positioned for FieldDisj<W> {
type Width = W;
fn mask(&self) -> W {
self.mask
}
fn in_position(&self) -> W {
self.val
}
}
impl<
W,
LM: Unsigned,
LO: Unsigned,
LU: Unsigned,
LR,
RM: Unsigned,
RO: Unsigned,
RU: Unsigned,
RR,
> Add<Field<W, RM, RO, RU, RR>> for Field<W, LM, LO, LU, LR>
where
LU: IsGreater<U0, Output = True> + ReifyTo<W>,
RU: IsGreater<U0, Output = True> + ReifyTo<W>,
RO: ReifyTo<W>,
LO: ReifyTo<W>,
W: Copy
+ Clone
+ PartialOrd
+ BitAnd<W, Output = W>
+ Shr<W, Output = W>
+ Default
+ Shl<W, Output = W>
+ BitOr<W, Output = W>,
U0: ReifyTo<W>,
LM: BitOr<RM>,
<LM as BitOr<RM>>::Output: ReifyTo<W>,
{
type Output = FieldDisj<W>;
fn add(self, rhs: Field<W, RM, RO, RU, RR>) -> Self::Output {
FieldDisj {
val: (self.val() << LO::reify()) | (rhs.val() << RO::reify()),
mask: <LM as BitOr<RM>>::Output::reify(),
}
}
}
impl<W, M: Unsigned, O: Unsigned, U: Unsigned, R> Add<FieldDisj<W>> for Field<W, M, O, U, R>
where
U: IsGreater<U0, Output = True> + ReifyTo<W>,
W: Copy
+ Clone
+ PartialOrd
+ BitAnd<W, Output = W>
+ Shr<W, Output = W>
+ Default
+ Shl<W, Output = W>
+ BitOr<W, Output = W>,
U0: ReifyTo<W>,
O: ReifyTo<W>,
M: ReifyTo<W>,
{
type Output = FieldDisj<W>;
fn add(self, rhs: FieldDisj<W>) -> Self::Output {
FieldDisj {
val: (self.val() << O::reify()) | rhs.val,
mask: M::reify() | rhs.mask(),
}
}
}
impl<W, M: Unsigned, O: Unsigned, U: Unsigned, R> Add<Field<W, M, O, U, R>> for FieldDisj<W>
where
U: IsGreater<U0, Output = True> + ReifyTo<W>,
W: Copy
+ Clone
+ PartialOrd
+ BitAnd<W, Output = W>
+ Shr<W, Output = W>
+ Default
+ Shl<W, Output = W>
+ BitOr<W, Output = W>,
U0: ReifyTo<W>,
O: ReifyTo<W>,
M: ReifyTo<W>,
{
type Output = FieldDisj<W>;
fn add(self, rhs: Field<W, M, O, U, R>) -> Self::Output {
FieldDisj {
val: self.val | (rhs.val() << O::reify()),
mask: self.mask | M::reify(),
}
}
}
pub trait Pointer {
unsafe fn ptr(&self) -> *mut usize;
}