use std::sync::OnceLock;
thread_local! {
                                    pub(crate) static READ_FN: OnceLock<fn(usize,usize)->u64> = OnceLock::new();
                                        pub (crate) static WRITE_FN: OnceLock<fn(usize,usize,u64)> = OnceLock::new();
    pub (crate) static LDMST: OnceLock<fn(usize,u64)> = OnceLock::new();
}
macro_rules! set_access_fn {
    ($CONST_ID:ident,$fn_id:ident,$fn_literal:literal,$access_fn_type:ty,$doc:literal) => {
        #[doc=$doc]
        pub fn $fn_id(fun: $access_fn_type) -> Result<(), String> {
            $CONST_ID.with(|function| {
                function.set(fun).or_else(|_| {
                    Err(format!(
                        "The thread local {} can only be set once.",
                        $fn_literal
                    ))
                })
            })
        }
    };
}
set_access_fn!(
    READ_FN,
    set_read_fn,
    "read_fn",
    fn(usize, usize) -> u64,
    "Set the function that is called when a read to a register happens\n through the PAC API.\n The function is called with the following arguments (in order):\n - a u64 representing the register address\n - a u64 representing the read mask (i.e. how many bits are read)\n This is necessary due to the way that the generated PACs handle\n generic register sizes.\n"
);
set_access_fn!(
    WRITE_FN,
    set_write_fn,
    "write_fn",
    fn(usize, usize, u64),
    "Set the function that is called when a write to a register happens\n through the PAC API.\n The function is called with the following arguments (in order):\n - a u64 representing the register address\n - a u64 representing the write mask (i.e. how many bits are read)\n This is necessary due to the way that the generated PACs handle\n generic register sizes.\n - a u64 representing the value that gets written to the register\n"
);
#[cfg(feature = "tracing")]
pub mod insanely_unsafe {
    use crate::common::sealed::{CastFrom, RegSpec};
    use crate::common::{Access, R, Read, Reg, W, Write};
    use crate::{RegValueT, RegisterValue};
    pub trait WriteOnlyRead: Access {}
    impl WriteOnlyRead for W {}
    pub trait ReadOnlyWrite: Access {}
    impl ReadOnlyWrite for R {}
    impl<T: RegSpec, A: WriteOnlyRead> Reg<T, A> {
                                                #[inline(always)]
        pub unsafe fn read_write_only(&self) -> RegValueT<T> {
            let val = {
                let mut buf: u64 = 0x0;
                super::READ_FN.with(|rf| {
                    buf = rf.get().unwrap()(self.addr(), std::mem::size_of::<T::DataType>());
                });
                T::DataType::cast_from(buf)
            };
            <RegValueT<_> as RegisterValue<_>>::new(val)
        }
    }
    impl<T: RegSpec, A: ReadOnlyWrite> Reg<T, A> {
                                                                                        #[inline(always)]
        pub unsafe fn write_read_only(&self, reg_value: RegValueT<T>) {
            super::WRITE_FN.with(|wf| {
                wf.get().unwrap()(
                    self.addr(),
                    std::mem::size_of::<T::DataType>(),
                    reg_value.data.into(),
                )
            });
        }
    }
    impl<T: Default + RegSpec, A: ReadOnlyWrite> Reg<T, A>
    where
        RegValueT<T>: Default,
    {
                                                                                        #[inline(always)]
                pub unsafe fn init_read_only(&self, f: impl FnOnce(RegValueT<T>) -> RegValueT<T>) {
            let val = RegValueT::<T>::default();
            let res = f(val);
            self.write_read_only(res);
        }
    }
    impl<T: RegSpec, A: WriteOnlyRead + Write> Reg<T, A> {
        #[inline(always)]
                                                                                                        pub unsafe fn modify_write_only(&self, f: impl FnOnce(RegValueT<T>) -> RegValueT<T>) {
            let val = self.read_write_only();
            let res = f(val);
            self.write(res);
        }
    }
    impl<T: RegSpec, A: Read + ReadOnlyWrite> Reg<T, A> {
        #[inline(always)]
                                                                                                        pub unsafe fn modify_read_only(&self, f: impl FnOnce(RegValueT<T>) -> RegValueT<T>) {
            let val = self.read();
            let res = f(val);
            self.write_read_only(res);
        }
    }
}