pub use crate::enums::IDeterminant;
use crate::enums::IDeterminantProvider;
use crate::padding::Padded;
use crate::Union;
use crate::{self as stabby, unreachable_unchecked, Bit, IStable};
#[stabby::stabby]
pub struct Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
niche_exporter: <Ok as IDeterminantProvider<Err>>::NicheExporter,
determinant: <Ok as IDeterminantProvider<Err>>::Determinant,
#[allow(clippy::type_complexity)]
union: core::mem::MaybeUninit<
Union<
Padded<<Ok as IDeterminantProvider<Err>>::OkShift, Ok>,
Padded<<Ok as IDeterminantProvider<Err>>::ErrShift, Err>,
>,
>,
}
impl<Ok: Clone, Err: Clone> Clone for Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
fn clone(&self) -> Self {
self.match_ref(|ok| Self::Ok(ok.clone()), |err| Self::Err(err.clone()))
}
}
impl<Ok, Err> core::fmt::Debug for Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
Ok: core::fmt::Debug,
Err: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.as_ref().fmt(f)
}
}
impl<Ok, Err> core::hash::Hash for Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
Ok: core::hash::Hash,
Err: core::hash::Hash,
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
if self.is_ok() {
true.hash(state);
unsafe { self.ok_unchecked() }.hash(state);
} else {
false.hash(state);
unsafe { self.err_unchecked() }.hash(state);
}
}
}
impl<Ok, Err> core::cmp::PartialEq for Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
Ok: core::cmp::PartialEq,
Err: core::cmp::PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (self.is_ok(), other.is_ok()) {
(true, true) => unsafe { self.ok_unchecked().eq(other.ok_unchecked()) },
(false, false) => unsafe { self.err_unchecked().eq(other.err_unchecked()) },
_ => false,
}
}
}
impl<Ok, Err> core::cmp::Eq for Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
Ok: core::cmp::Eq,
Err: core::cmp::Eq,
{
}
impl<Ok, Err> From<core::result::Result<Ok, Err>> for Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
fn from(value: core::result::Result<Ok, Err>) -> Self {
match value {
Ok(value) => Self::Ok(value),
Err(value) => Self::Err(value),
}
}
}
impl<Ok, Err> From<Result<Ok, Err>> for core::result::Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
fn from(value: Result<Ok, Err>) -> Self {
value.match_owned(Ok, Err)
}
}
impl<Ok, Err> Drop for Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
fn drop(&mut self) {
if self.is_ok() {
unsafe { core::ptr::drop_in_place(&mut self.union.assume_init_mut().ok.value) }
} else {
unsafe { core::ptr::drop_in_place(&mut self.union.assume_init_mut().err.value) }
}
}
}
impl<Ok, Err> Result<Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
#[allow(non_snake_case)]
pub fn Ok(value: Ok) -> Self {
let mut union = core::mem::MaybeUninit::new(Union {
ok: core::mem::ManuallyDrop::new(Padded {
lpad: Default::default(),
value,
}),
});
let determinant = unsafe {
<Ok as IDeterminantProvider<Err>>::Determinant::ok(union.as_mut_ptr().cast())
};
Self {
niche_exporter: Default::default(),
determinant,
union,
}
}
#[allow(non_snake_case)]
pub fn Err(value: Err) -> Self {
let mut union = core::mem::MaybeUninit::new(Union {
err: core::mem::ManuallyDrop::new(Padded {
lpad: Default::default(),
value,
}),
});
let determinant = unsafe {
<Ok as IDeterminantProvider<Err>>::Determinant::err(union.as_mut_ptr().cast())
};
Self {
niche_exporter: Default::default(),
determinant,
union,
}
}
#[allow(clippy::missing_errors_doc)]
pub fn as_ref(&self) -> core::result::Result<&Ok, &Err> {
self.match_ref(Ok, Err)
}
pub fn match_ref<'a, U, FnOk: FnOnce(&'a Ok) -> U, FnErr: FnOnce(&'a Err) -> U>(
&'a self,
ok: FnOk,
err: FnErr,
) -> U {
if self.is_ok() {
unsafe { ok(self.ok_unchecked()) }
} else {
unsafe { err(self.err_unchecked()) }
}
}
pub fn match_ref_ctx<'a, T, U, FnOk: FnOnce(T, &'a Ok) -> U, FnErr: FnOnce(T, &'a Err) -> U>(
&'a self,
ctx: T,
ok: FnOk,
err: FnErr,
) -> U {
if self.is_ok() {
unsafe { ok(ctx, self.ok_unchecked()) }
} else {
unsafe { err(ctx, self.err_unchecked()) }
}
}
pub fn match_mut<
'a,
U,
FnOk: FnOnce(OkGuard<'a, Ok, Err>) -> U,
FnErr: FnOnce(ErrGuard<'a, Ok, Err>) -> U,
>(
&'a mut self,
ok: FnOk,
err: FnErr,
) -> U {
let r;
if Self::is_ok(self) {
unsafe {
r = ok(self.ok_mut_unchecked());
}
} else {
unsafe {
r = err(self.err_mut_unchecked());
}
}
r
}
pub fn match_mut_ctx<
'a,
T,
U,
FnOk: FnOnce(T, OkGuard<'a, Ok, Err>) -> U,
FnErr: FnOnce(T, ErrGuard<'_, Ok, Err>) -> U,
>(
&'a mut self,
ctx: T,
ok: FnOk,
err: FnErr,
) -> U {
let r;
if Self::is_ok(self) {
unsafe {
r = ok(ctx, self.ok_mut_unchecked());
}
} else {
unsafe {
r = err(ctx, self.err_mut_unchecked());
}
}
r
}
pub fn match_owned<U, FnOk: FnOnce(Ok) -> U, FnErr: FnOnce(Err) -> U>(
self,
ok: FnOk,
err: FnErr,
) -> U {
let is_ok = self.is_ok();
let union = unsafe { self.union.assume_init_read() };
core::mem::forget(self);
if is_ok {
ok(core::mem::ManuallyDrop::into_inner(unsafe { union.ok }).value)
} else {
err(core::mem::ManuallyDrop::into_inner(unsafe { union.err }).value)
}
}
pub fn match_owned_ctx<U, T, FnOk: FnOnce(T, Ok) -> U, FnErr: FnOnce(T, Err) -> U>(
self,
ctx: T,
ok: FnOk,
err: FnErr,
) -> U {
let is_ok = self.is_ok();
let union = unsafe { self.union.assume_init_read() };
core::mem::forget(self);
if is_ok {
ok(
ctx,
core::mem::ManuallyDrop::into_inner(unsafe { union.ok }).value,
)
} else {
err(
ctx,
core::mem::ManuallyDrop::into_inner(unsafe { union.err }).value,
)
}
}
pub fn is_ok(&self) -> bool {
self.determinant
.is_det_ok(&self.union as *const _ as *const _)
}
pub fn is_err(&self) -> bool {
!self.is_ok()
}
pub fn ok(self) -> Option<Ok> {
self.match_owned(Some, |_| None)
}
pub fn err(self) -> Option<Err> {
self.match_owned(|_| None, Some)
}
pub fn ok_ref(&self) -> Option<&Ok> {
self.match_ref(Some, |_| None)
}
pub fn err_ref(&self) -> Option<&Err> {
self.match_ref(|_| None, Some)
}
pub fn ok_mut(&mut self) -> Option<OkGuard<'_, Ok, Err>> {
self.match_mut(Some, |_| None)
}
pub fn err_mut(&mut self) -> Option<ErrGuard<'_, Ok, Err>> {
self.match_mut(|_| None, Some)
}
pub fn map<F: FnOnce(Ok) -> U, U>(self, f: F) -> Result<U, Err>
where
U: IDeterminantProvider<Err>,
{
self.match_owned(move |x| Result::Ok(f(x)), |x| Result::Err(x))
}
pub fn and_then<F: FnOnce(Ok) -> Result<U, Err>, U>(self, f: F) -> Result<U, Err>
where
U: IDeterminantProvider<Err>,
{
self.match_owned(f, |x| Result::Err(x))
}
pub fn unwrap_or_else<F: FnOnce(Err) -> Ok>(self, f: F) -> Ok {
self.match_owned(|x| x, f)
}
pub unsafe fn unwrap_unchecked(self) -> Ok {
self.unwrap_or_else(|_| unsafe { unreachable_unchecked!() })
}
pub fn unwrap(self) -> Ok
where
Err: core::fmt::Debug,
{
self.unwrap_or_else(|e| panic!("Result::unwrap called on Err variant: {e:?}"))
}
pub fn unwrap_err_or_else<F: FnOnce(Ok) -> Err>(self, f: F) -> Err {
self.match_owned(f, |x| x)
}
pub unsafe fn unwrap_err_unchecked(self) -> Err {
self.unwrap_err_or_else(|_| unsafe { unreachable_unchecked!() })
}
pub fn unwrap_err(self) -> Err
where
Ok: core::fmt::Debug,
{
self.unwrap_err_or_else(|e| panic!("Result::unwrap_err called on Ok variant: {e:?}"))
}
unsafe fn ok_unchecked(&self) -> &Ok {
&self.union.assume_init_ref().ok.value
}
unsafe fn err_unchecked(&self) -> &Err {
&self.union.assume_init_ref().err.value
}
unsafe fn ok_mut_unchecked(&mut self) -> OkGuard<'_, Ok, Err> {
OkGuard { inner: self }
}
unsafe fn err_mut_unchecked(&mut self) -> ErrGuard<Ok, Err> {
ErrGuard { inner: self }
}
}
pub struct OkGuard<'a, Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
inner: &'a mut Result<Ok, Err>,
}
impl<'a, Ok, Err> core::ops::Deref for OkGuard<'a, Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
type Target = Ok;
fn deref(&self) -> &Self::Target {
unsafe { &self.inner.union.assume_init_ref().ok.value }
}
}
impl<'a, Ok, Err> core::ops::DerefMut for OkGuard<'a, Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut self.inner.union.assume_init_mut().ok.value }
}
}
impl<'a, Ok, Err> Drop for OkGuard<'a, Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
fn drop(&mut self) {
if <<<Ok as IDeterminantProvider<Err>>::Determinant as IDeterminant>::IsNicheTrick as Bit>::BOOL {
unsafe {
<Ok as IDeterminantProvider<Err>>::Determinant::ok(self.inner.union.as_mut_ptr().cast())
};
}
}
}
pub struct ErrGuard<'a, Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
inner: &'a mut Result<Ok, Err>,
}
impl<'a, Ok, Err> core::ops::Deref for ErrGuard<'a, Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
type Target = Err;
fn deref(&self) -> &Self::Target {
unsafe { &self.inner.union.assume_init_ref().err.value }
}
}
impl<'a, Ok, Err> core::ops::DerefMut for ErrGuard<'a, Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut self.inner.union.assume_init_mut().err.value }
}
}
impl<'a, Ok, Err> Drop for ErrGuard<'a, Ok, Err>
where
Ok: IDeterminantProvider<Err>,
Err: IStable,
{
fn drop(&mut self) {
if <<<Ok as IDeterminantProvider<Err>>::Determinant as IDeterminant>::IsNicheTrick as Bit>::BOOL {
unsafe {
<Ok as IDeterminantProvider<Err>>::Determinant::err(
self.inner.union.as_mut_ptr().cast(),
)
};
}
}
}