#![allow(clippy::inline_always)]
use core::convert::Infallible;
use crate::{
access::{Access, Read, Write},
endian::Endian,
io::{PtrIO, RegisterIO},
};
use num_traits::{
AsPrimitive, FromBytes, PrimInt, ToBytes, WrappingAdd, WrappingSub, identities::ConstZero,
};
pub trait RegInt:
PrimInt
+ ConstZero
+ WrappingSub
+ WrappingAdd
+ FromBytes<Bytes: for<'a> TryFrom<&'a [u8], Error: core::fmt::Debug>>
+ ToBytes<Bytes: AsRef<[u8]>>
+ core::fmt::Debug
+ 'static
{
}
impl RegInt for u8 {}
impl RegInt for u16 {}
impl RegInt for u32 {}
impl RegInt for u64 {}
impl RegInt for u128 {}
impl RegInt for i8 {}
impl RegInt for i16 {}
impl RegInt for i32 {}
impl RegInt for i64 {}
impl RegInt for i128 {}
pub trait Register: Copy {
type Regwidth: RegInt + AsPrimitive<Self::Accesswidth>;
type Accesswidth: RegInt + AsPrimitive<Self::Regwidth>;
type Access: Access;
type ByteEndian: Endian;
type WordEndian: Endian;
unsafe fn from_raw(val: Self::Regwidth) -> Self;
fn to_raw(self) -> Self::Regwidth;
}
#[derive(Debug, PartialEq, Eq)]
pub struct Reg<'io, R: Register, IO: RegisterIO = PtrIO> {
ptr: *mut R::Regwidth,
io: &'io IO,
}
impl<R: Register, IO: RegisterIO> Copy for Reg<'_, R, IO> where R::Regwidth: Copy {}
impl<R: Register, IO: RegisterIO> Clone for Reg<'_, R, IO>
where
R::Regwidth: Clone,
{
fn clone(&self) -> Self {
*self
}
}
unsafe impl<R: Register, IO: RegisterIO + Sync> Send for Reg<'_, R, IO> {}
unsafe impl<R: Register, IO: RegisterIO + Sync> Sync for Reg<'_, R, IO> {}
impl<R: Register> Reg<'static, R, PtrIO> {
#[inline(always)]
pub const unsafe fn from_ptr(ptr: *mut R::Regwidth) -> Self {
Self { ptr, io: &PtrIO }
}
}
impl<'io, R: Register, IO: RegisterIO> Reg<'io, R, IO> {
#[inline(always)]
pub const unsafe fn from_ptr_with(ptr: *mut R::Regwidth, io: &'io IO) -> Self {
Self { ptr, io }
}
#[inline(always)]
#[must_use]
pub const fn as_ptr(&self) -> *mut R {
self.ptr.cast()
}
}
impl<R: Register, IO: RegisterIO> Reg<'_, R, IO>
where
R::Access: Read,
{
#[inline(always)]
#[allow(clippy::missing_errors_doc)]
pub fn try_read(&self) -> Result<R, IO::Error> {
unsafe { self.io.try_read_register(self.ptr) }
}
}
impl<R: Register, IO: RegisterIO<Error = Infallible>> Reg<'_, R, IO>
where
R::Access: Read,
{
#[inline(always)]
#[allow(clippy::must_use_candidate)]
pub fn read(&self) -> R {
self.try_read().unwrap_infallible()
}
}
impl<R: Register, IO: RegisterIO> Reg<'_, R, IO>
where
R::Access: Write,
{
#[inline(always)]
#[allow(clippy::missing_errors_doc)]
pub fn try_write_value(&self, val: R) -> Result<(), IO::Error> {
unsafe { self.io.try_write_register(self.ptr, val) }
}
}
impl<R: Register, IO: RegisterIO<Error = Infallible>> Reg<'_, R, IO>
where
R::Access: Write,
{
#[inline(always)]
pub fn write_value(&self, val: R) {
self.try_write_value(val).unwrap_infallible();
}
}
impl<R: Default + Register, IO: RegisterIO> Reg<'_, R, IO>
where
R::Access: Write,
{
#[inline(always)]
#[allow(clippy::missing_errors_doc)]
pub fn try_write<T>(&self, f: impl FnOnce(&mut R) -> T) -> Result<T, IO::Error> {
let mut val = Default::default();
let res = f(&mut val);
self.try_write_value(val)?;
Ok(res)
}
}
impl<R: Default + Register, IO: RegisterIO<Error = Infallible>> Reg<'_, R, IO>
where
R::Access: Write,
{
#[inline(always)]
pub fn write<T>(&self, f: impl FnOnce(&mut R) -> T) -> T {
self.try_write(f).unwrap_infallible()
}
}
impl<R: Register, IO: RegisterIO> Reg<'_, R, IO>
where
R::Access: Read + Write,
{
#[inline(always)]
#[allow(clippy::missing_errors_doc)]
pub fn try_modify<T>(&self, f: impl FnOnce(&mut R) -> T) -> Result<T, IO::Error> {
let mut val = self.try_read()?;
let res = f(&mut val);
self.try_write_value(val)?;
Ok(res)
}
}
impl<R: Register, IO: RegisterIO<Error = Infallible>> Reg<'_, R, IO>
where
R::Access: Read + Write,
{
#[inline(always)]
pub fn modify<T>(&self, f: impl FnOnce(&mut R) -> T) -> T {
self.try_modify(f).unwrap_infallible()
}
}
trait UnwrapInfallible {
type T;
fn unwrap_infallible(self) -> Self::T;
}
impl<T> UnwrapInfallible for Result<T, Infallible> {
type T = T;
fn unwrap_infallible(self) -> T {
match self {
Ok(v) => v,
Err(e) => match e {}, }
}
}