#![doc = include_str!("../README.md")]
#![no_std]
#![cfg_attr(feature = "const_trait_impl", feature(const_trait_impl))]
#![cfg_attr(feature = "core_intrinsics", feature(core_intrinsics))]
#![cfg_attr(
feature = "adt_const_params",
allow(incomplete_features),
feature(adt_const_params)
)]
#![cfg_attr(
feature = "const_precise_live_drops",
feature(const_precise_live_drops)
)]
use core::mem::{ManuallyDrop, MaybeUninit};
pub mod prelude;
#[repr(transparent)]
pub struct CTOption<T, const IS_SOME_VAL: bool>(MaybeUninit<T>);
pub const IS_SOME: bool = true;
pub const IS_NONE: bool = false;
pub type CTSome<T> = CTOption<T, true>;
pub type CTNone<T> = CTOption<T, false>;
#[doc(hidden)]
pub unsafe trait OptionalConstGeneric {
type Inner;
const IS_SOME_VAL: bool;
}
#[cfg(feature = "adt_const_params")]
pub mod workarounds {
use core::marker::ConstParamTy;
#[derive(Eq, PartialEq, ConstParamTy)]
pub enum Option<T> {
Some(T),
None,
}
impl<T> Option<T> {
#[cfg(feature = "const_precise_live_drops")]
pub const fn into_core(self) -> core::option::Option<T> {
match self {
Self::Some(x) => core::option::Option::Some(x),
Self::None => core::option::Option::None,
}
}
}
}
unsafe impl<T, const IS_SOME_VAL: bool> OptionalConstGeneric for CTOption<T, IS_SOME_VAL> {
type Inner = T;
const IS_SOME_VAL: bool = IS_SOME_VAL;
}
#[cfg(feature = "core_intrinsics")]
pub mod opt_const_generic {
use super::{CTSome, OptionalConstGeneric};
use core::mem::MaybeUninit;
pub const fn to_option<T: OptionalConstGeneric>(opt: T) -> Option<T::Inner> {
let storage: MaybeUninit<T::Inner> = unsafe { core::intrinsics::transmute_unchecked(opt) };
match T::IS_SOME_VAL {
true => {
let opt = unsafe { CTSome::<T::Inner>::from_maybe_uninit(storage) };
Some(opt.into_inner())
}
false => None,
}
}
}
impl<T> CTSome<T> {
pub const fn new(val: T) -> Self {
Self(MaybeUninit::new(val))
}
#[doc(alias = "unwrap")]
pub const fn into_inner(self) -> T {
union CTSomeUnion<T> {
md_ctsome: ManuallyDrop<CTSome<T>>,
md_inner: ManuallyDrop<T>,
}
let md_ctsome = ManuallyDrop::new(self);
let u = CTSomeUnion { md_ctsome };
let md_inner = unsafe { u.md_inner };
ManuallyDrop::into_inner(md_inner)
}
pub const unsafe fn assume_const_generic_val<const IS_SOME_VAL: bool>(
self,
) -> CTOption<T, IS_SOME_VAL> {
union CTOptionVariantUnion<U, const NESTED_IS_SOME_VAL: bool> {
md_ctsome: ManuallyDrop<CTSome<U>>,
md_ctopt: ManuallyDrop<CTOption<U, NESTED_IS_SOME_VAL>>,
}
let md_ctsome = ManuallyDrop::new(self);
let u = CTOptionVariantUnion { md_ctsome };
let md_ctopt = unsafe { u.md_ctopt };
ManuallyDrop::into_inner(md_ctopt)
}
}
impl<T> CTNone<T> {
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Self(MaybeUninit::uninit())
}
pub const fn insert(mut self, val: T) -> CTSome<T> {
union CTOptionVariantUnion<T> {
md_ctsome: ManuallyDrop<CTSome<T>>,
md_ctnone: ManuallyDrop<CTNone<T>>,
}
self.0 = MaybeUninit::new(val);
let md_ctnone = ManuallyDrop::new(self);
let u = CTOptionVariantUnion { md_ctnone };
let md_ctsome = unsafe { u.md_ctsome };
ManuallyDrop::into_inner(md_ctsome)
}
pub const fn forget(self) {
core::mem::forget(self);
}
pub const unsafe fn assume_const_generic_val<const IS_SOME_VAL: bool>(
self,
) -> CTOption<T, IS_SOME_VAL> {
union CTOptionVariantUnion<U, const NESTED_IS_SOME_VAL: bool> {
md_ctnone: ManuallyDrop<CTNone<U>>,
md_ctopt: ManuallyDrop<CTOption<U, NESTED_IS_SOME_VAL>>,
}
let md_ctnone = ManuallyDrop::new(self);
let u = CTOptionVariantUnion { md_ctnone };
let md_ctopt = unsafe { u.md_ctopt };
ManuallyDrop::into_inner(md_ctopt)
}
}
impl<T, const IS_SOME_VAL: bool> CTOption<T, IS_SOME_VAL> {
pub const unsafe fn from_maybe_uninit(val: MaybeUninit<T>) -> Self {
Self(val)
}
pub const fn is_some(&self) -> bool {
IS_SOME_VAL
}
pub const unsafe fn assume_some(self) -> CTSome<T> {
union CTOptionVariantUnion<U, const NESTED_IS_SOME_VAL: bool> {
md_ctsome: ManuallyDrop<CTSome<U>>,
md_ctopt: ManuallyDrop<CTOption<U, NESTED_IS_SOME_VAL>>,
}
let md_ctopt = ManuallyDrop::new(self);
let u = CTOptionVariantUnion { md_ctopt };
let md_ctsome = unsafe { u.md_ctsome };
ManuallyDrop::into_inner(md_ctsome)
}
pub const unsafe fn assume_none(self) -> CTNone<T> {
union CTOptionVariantUnion<U, const NESTED_IS_SOME_VAL: bool> {
md_ctnone: ManuallyDrop<CTNone<U>>,
md_ctopt: ManuallyDrop<CTOption<U, NESTED_IS_SOME_VAL>>,
}
let md_ctopt = ManuallyDrop::new(self);
let u = CTOptionVariantUnion { md_ctopt };
let md_ctnone = unsafe { u.md_ctnone };
ManuallyDrop::into_inner(md_ctnone)
}
}
#[cfg(not(feature = "const_trait_impl"))]
impl<T, const IS_SOME_VAL: bool> Drop for CTOption<T, IS_SOME_VAL> {
fn drop(&mut self) {
if IS_SOME_VAL {
unsafe { self.0.assume_init_drop() }
}
}
}
#[cfg(feature = "const_trait_impl")]
macro_rules! provide_items_guarded_by_const_trait_impl {
() => {
pub const fn const_drop<T: ~const core::marker::Destruct>(val: T) {
core::mem::forget(val);
}
impl<T, const IS_SOME_VAL: bool> const Drop for CTOption<T, IS_SOME_VAL> {
fn drop(&mut self) {
if IS_SOME_VAL {
unsafe { self.0.assume_init_drop() }
}
}
}
};
}
#[cfg(feature = "const_trait_impl")]
provide_items_guarded_by_const_trait_impl!();
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
const fn into_inner_works() {
let opt = CTSome::new(3);
let v = opt.into_inner();
if v != 3 {
panic!("v != 3");
}
}
#[test]
const fn test_insert() {
let none = CTNone::<i32>::new();
let some = none.insert(42);
assert!(some.into_inner() == 42);
}
}