use core::fmt::Debug;
pub unsafe trait GbaCellSafe: Copy {}
unsafe impl<T> GbaCellSafe for T where T: Copy {}
#[repr(transparent)]
pub struct GbaCell<T>(core::cell::UnsafeCell<T>);
#[cfg(feature = "on_gba")]
impl<T> Debug for GbaCell<T>
where
T: GbaCellSafe + Debug,
{
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
<T as Debug>::fmt(&self.read(), f)
}
}
impl<T> Default for GbaCell<T>
where
T: GbaCellSafe + Default,
{
#[inline]
#[must_use]
fn default() -> Self {
Self::new(T::default())
}
}
#[cfg(feature = "on_gba")]
impl<T> Clone for GbaCell<T>
where
T: GbaCellSafe + Default,
{
#[inline]
#[must_use]
fn clone(&self) -> Self {
Self::new(self.read())
}
}
#[cfg(feature = "on_gba")]
unsafe impl<T> Sync for GbaCell<T> {}
impl<T> GbaCell<T>
where
T: GbaCellSafe,
{
const _ASSERT_GBACELL_SAFE: () = {
let size = core::mem::size_of::<T>();
let align = core::mem::align_of::<T>();
match (size, align) {
(1, 1) | (2, 2) | (4, 4) => {}
_ => {
panic!("Provided type cannot be made GbaCell-safe! Expected a size & align of 1, 2, or 4.")
}
}
};
#[inline]
#[must_use]
pub const fn new(t: T) -> Self {
Self(core::cell::UnsafeCell::new(t))
}
#[inline]
#[must_use]
#[cfg(feature = "on_gba")]
#[cfg_attr(feature = "track_caller", track_caller)]
pub fn read(&self) -> T {
unsafe { self.0.get().read_volatile() }
}
#[inline]
#[cfg(feature = "on_gba")]
#[cfg_attr(feature = "track_caller", track_caller)]
pub fn write(&self, t: T) {
unsafe { self.0.get().write_volatile(t) }
}
}