use bytemuck::{Pod, Zeroable};
use const_default::ConstDefault;
pub trait Uncheckable: Copy {
type UncheckedRaw: Copy;
fn raw_value(sf: Self) -> Self::UncheckedRaw;
fn try_from_raw_value(raw: Self::UncheckedRaw) -> Result<Self, Self::UncheckedRaw>;
}
pub unsafe trait PlainUncheckable: Uncheckable {}
#[derive(Debug)]
#[repr(transparent)]
pub struct Unchecked<T: Uncheckable> {
raw: T::UncheckedRaw,
}
impl<T: Uncheckable> Unchecked<T> {
pub const fn raw_value(self) -> T::UncheckedRaw {
self.raw
}
pub const fn new_with_raw_value(raw: T::UncheckedRaw) -> Self {
Self { raw }
}
pub const fn raw_ref(&self) -> &T::UncheckedRaw {
&self.raw
}
pub fn get(self) -> Result<T, T::UncheckedRaw> {
T::try_from_raw_value(self.raw)
}
pub unsafe fn get_unchecked(self) -> T {
unsafe { self.get().unwrap_unchecked() }
}
pub fn get_or_default(self) -> T
where
T: Default,
{
self.get().unwrap_or_default()
}
}
impl<T: Uncheckable<UncheckedRaw: Uncheckable>> Unchecked<Unchecked<T>> {
pub fn flatten_get(self) -> Result<T, <T::UncheckedRaw as Uncheckable>::UncheckedRaw> {
T::try_from_raw_value(T::UncheckedRaw::try_from_raw_value(self.raw)?).map_err(|_| self.raw)
}
pub unsafe fn flatten_get_unchecked(self) -> T {
unsafe { self.flatten_get().unwrap_unchecked() }
}
pub fn flatten_get_or_default(self) -> T
where
T: Default,
{
self.flatten_get().unwrap_or_default()
}
}
impl<T: Uncheckable<UncheckedRaw: ConstDefault>> ConstDefault for Unchecked<T> {
const DEFAULT: Self = Self { raw: ConstDefault::DEFAULT };
}
impl<T: Uncheckable<UncheckedRaw: Default>> Default for Unchecked<T> {
fn default() -> Self {
Self { raw: Default::default() }
}
}
impl<T: Uncheckable> Copy for Unchecked<T> {}
impl<T: Uncheckable> Clone for Unchecked<T> {
fn clone(&self) -> Self {
*self
}
}
unsafe impl<T: Uncheckable<UncheckedRaw: Zeroable>> Zeroable for Unchecked<T> {}
unsafe impl<T: Uncheckable<UncheckedRaw: Pod> + 'static> Pod for Unchecked<T> {}
impl<T: Uncheckable<UncheckedRaw: Uncheckable>> Uncheckable for Unchecked<T> {
type UncheckedRaw = <T::UncheckedRaw as Uncheckable>::UncheckedRaw;
fn raw_value(sf: Self) -> Self::UncheckedRaw {
T::UncheckedRaw::raw_value(sf.raw)
}
fn try_from_raw_value(raw: Self::UncheckedRaw) -> Result<Self, Self::UncheckedRaw> {
Ok(Self { raw: T::UncheckedRaw::try_from_raw_value(raw)? })
}
}
unsafe impl<T: Uncheckable<UncheckedRaw: Uncheckable + PlainUncheckable> + PlainUncheckable> PlainUncheckable for Unchecked<T> {}
impl<T: Uncheckable> From<T> for Unchecked<T> {
fn from(value: T) -> Self {
Self { raw: T::raw_value(value) }
}
}
impl<T: Uncheckable<UncheckedRaw: PartialEq>> PartialEq<Unchecked<T>> for Unchecked<T> {
fn eq(&self, other: &Unchecked<T>) -> bool {
self.raw == other.raw
}
}
impl<T: Uncheckable<UncheckedRaw: Eq>> Eq for Unchecked<T> {}
impl<T: Uncheckable<UncheckedRaw: PartialEq>> PartialEq<T> for Unchecked<T> {
fn eq(&self, other: &T) -> bool {
self.raw == T::raw_value(*other)
}
}
impl Uncheckable for bool {
type UncheckedRaw = u8;
fn raw_value(sf: Self) -> Self::UncheckedRaw {
sf as u8
}
fn try_from_raw_value(raw: Self::UncheckedRaw) -> Result<Self, Self::UncheckedRaw> {
if raw & 1 == raw { Ok(raw != 0) } else { Err(raw) }
}
}
impl Unchecked<bool> {
pub const fn masked_value(&self) -> bool {
self.raw & 1 != 0
}
}