use core::marker::Destruct;
use core::marker::Freeze;
use crate::const_helpers as ch;
use crate::set;
use crate::sure_eq::SureEq;
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Sure<T: SureEq + 'static, const SET: &'static [T]>(T);
impl<T, const SET: &'static [T]> Sure<T, SET>
where
T: Copy + const Destruct + Freeze + SureEq + const Ord + 'static,
{
pub const SET: &'static [T] = SET;
#[must_use]
pub const fn set(&self) -> &'static [T] {
SET
}
pub const fn new(value: T) -> Result<Self, T> {
match Self::set_contains(&value) {
true => Ok(
unsafe { Self::new_unchecked(value) },
),
false => Err(value),
}
}
pub const fn new_via_binary_search(value: T) -> Result<Self, T> {
match Self::set_contains_via_binary_search(&value) {
true => Ok(
unsafe { Self::new_unchecked(value) },
),
false => Err(value),
}
}
#[must_use]
pub const unsafe fn new_unchecked(value: T) -> Self {
debug_assert!(
Self::set_contains(&value),
"Tried to create a Sure with a value thats not contained in its SET, this is UB."
);
Self(value)
}
#[must_use]
pub const fn set_contains(value: &T) -> bool {
ch::slice_contains(SET, value)
}
#[must_use]
pub const fn set_contains_via_binary_search(value: &T) -> bool {
SET.binary_search(value).is_ok()
}
#[must_use]
pub const fn inner(self) -> T {
self.0
}
#[must_use]
pub const fn sort(self) -> Sure<T, { set::SORT::<T, SET> }> {
unsafe { self.cast_unchecked() }
}
#[must_use]
pub const fn normalize(self) -> Sure<T, { set::NORMALIZE::<T, SET> }> {
unsafe { self.cast_unchecked() }
}
#[must_use]
pub const fn widen<const SUPER_SET: &'static [T]>(self) -> Sure<T, SUPER_SET> {
ch::const_assert!(
ch::slice_is_subset(SET, SUPER_SET),
"Tried to widen a Sure which failed because the target's SET isn't a superset of the original."
);
unsafe { self.cast_unchecked() }
}
pub const fn cast<const NEW_SET: &'static [T]>(self) -> Result<Sure<T, NEW_SET>, Self> {
match Sure::<T, NEW_SET>::set_contains(&self.inner()) {
true => Ok(
unsafe { self.cast_unchecked() },
),
false => Err(self),
}
}
#[must_use]
pub const unsafe fn cast_unchecked<const NEW_SET: &'static [T]>(self) -> Sure<T, NEW_SET> {
unsafe { Sure::new_unchecked(self.inner()) }
}
}