use core::convert::TryFrom;
use core::convert::TryInto;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::pin::Pin;
use crate::new::New;
use crate::new::TryNew;
#[inline]
pub unsafe fn by_raw<T, F>(f: F) -> impl New<Output = T>
where
F: FnOnce(Pin<&mut MaybeUninit<T>>),
{
struct FnNew<F, T> {
f: F,
_ph: PhantomData<fn(T)>,
}
unsafe impl<F, T> New for FnNew<F, T>
where
F: FnOnce(Pin<&mut MaybeUninit<T>>),
{
type Output = T;
#[inline]
unsafe fn new(self, this: Pin<&mut MaybeUninit<Self::Output>>) {
(self.f)(this)
}
}
FnNew::<F, T> {
f,
_ph: PhantomData,
}
}
#[inline]
pub fn by<T, F>(f: F) -> impl New<Output = T>
where
F: FnOnce() -> T,
{
unsafe { by_raw(|mut this| this.set(MaybeUninit::new(f()))) }
}
#[inline]
pub fn from<T: From<U>, U>(val: U) -> impl New<Output = T> {
by(|| val.into())
}
#[inline]
pub fn of<T>(val: T) -> impl New<Output = T> {
by(|| val)
}
#[inline]
pub fn default<T: Default>() -> impl New<Output = T> {
by(Default::default)
}
#[inline]
pub unsafe fn try_by_raw<T, E, F>(f: F) -> impl TryNew<Output = T, Error = E>
where
F: FnOnce(Pin<&mut MaybeUninit<T>>) -> Result<(), E>,
{
struct FnNew<F, T, E> {
f: F,
_ph: PhantomData<fn(T) -> E>,
}
unsafe impl<F, T, E> TryNew for FnNew<F, T, E>
where
F: FnOnce(Pin<&mut MaybeUninit<T>>) -> Result<(), E>,
{
type Output = T;
type Error = E;
#[inline]
unsafe fn try_new(
self,
this: Pin<&mut MaybeUninit<Self::Output>>,
) -> Result<(), E> {
(self.f)(this)
}
}
FnNew::<F, T, E> {
f,
_ph: PhantomData,
}
}
#[inline]
pub fn try_by<T, E, F>(f: F) -> impl TryNew<Output = T, Error = E>
where
F: FnOnce() -> Result<T, E>,
{
unsafe {
try_by_raw(|this| {
this.get_unchecked_mut().write(f()?);
Ok(())
})
}
}
#[inline]
pub fn try_from<T: TryFrom<U>, U>(
val: U,
) -> impl TryNew<Output = T, Error = T::Error> {
try_by(|| val.try_into())
}