use core::marker::PhantomPinned;
use core::mem;
use core::pin::Pin;
pub(crate) enum UnfoldStateProj<'pin, T, R> {
#[allow(dead_code)]
Value {
value: &'pin mut T,
},
Future {
future: Pin<&'pin mut R>,
},
Empty,
}
pub(crate) enum UnfoldStateProjReplace<T, R> {
Value {
value: T,
},
#[allow(dead_code)]
Future {
future: R,
},
Empty,
}
#[derive(Debug)]
pub(crate) enum UnfoldState<T, R> {
Value {
value: T,
},
Future {
future: R,
_pin: PhantomPinned,
},
Empty,
}
impl<T, R> UnfoldState<T, R> {
pub(crate) fn project(self: Pin<&mut Self>) -> UnfoldStateProj<'_, T, R> {
unsafe {
match self.get_unchecked_mut() {
UnfoldState::Value { value } => UnfoldStateProj::Value { value },
UnfoldState::Future { future, _pin } => UnfoldStateProj::Future {
future: Pin::new_unchecked(future),
},
UnfoldState::Empty => UnfoldStateProj::Empty,
}
}
}
pub(crate) fn project_replace(self: Pin<&mut Self>, new: Self) -> UnfoldStateProjReplace<T, R> {
unsafe {
let old = mem::replace(self.get_unchecked_mut(), new);
match old {
UnfoldState::Value { value } => UnfoldStateProjReplace::Value { value },
UnfoldState::Future { future, _pin } => UnfoldStateProjReplace::Future { future },
UnfoldState::Empty => UnfoldStateProjReplace::Empty,
}
}
}
pub(crate) fn project_future(self: Pin<&mut Self>) -> Option<Pin<&mut R>> {
match self.project() {
UnfoldStateProj::Future { future } => Some(future),
_ => None,
}
}
pub(crate) fn take_value(self: Pin<&mut Self>) -> Option<T> {
match &*self {
Self::Value { .. } => {
match self.project_replace(Self::Empty) {
UnfoldStateProjReplace::Value { value } => Some(value),
_ => unreachable!(),
}
}
_ => None,
}
}
}
impl<T: Unpin, R> Unpin for UnfoldState<T, R> {}