use std::{
future::Ready,
pin::Pin,
task::{Context, Poll},
};
use pin_project_lite::pin_project;
use topcoat_core::error::Result;
use super::yielder::DriveFuture;
use crate::{
View, ViewFirst, ViewSwap,
internal::yielder::{poll_first, poll_swap},
};
pin_project! {
pub struct MoveView<Fut> {
#[pin]
body: Fut,
}
}
impl<Fut> MoveView<Fut>
where
Fut: Future<Output = Result<()>>,
{
#[doc(hidden)]
pub fn new(body: Fut) -> Self {
Self { body }
}
}
impl MoveView<Ready<()>> {
pub fn drive<V: View>(view: V) -> impl Future<Output = Result<()>> {
DriveFuture::new(view)
}
}
impl<Fut> View for MoveView<Fut>
where
Fut: Future<Output = Result<()>> + Send,
{
fn poll_first(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<ViewFirst>> {
let this = self.project();
match poll_first(this.body, cx) {
(Poll::Pending, Some(first)) => Poll::Ready(Ok(first)),
(Poll::Pending, None) => Poll::Pending,
(Poll::Ready(_), Some(_)) => {
panic!("move view future yielded without returning pending")
}
(Poll::Ready(Err(e)), None) => Poll::Ready(Err(e)),
(Poll::Ready(Ok(())), None) => {
panic!("move view future completed without yielding anything")
}
}
}
fn poll_swap(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<Option<ViewSwap>>> {
let this = self.project();
match poll_swap(this.body, cx) {
(Poll::Pending, Some(swap)) => Poll::Ready(Ok(Some(swap))),
(Poll::Pending, None) => Poll::Pending,
(Poll::Ready(_), Some(_)) => {
panic!("move view future yielded without returning pending")
}
(Poll::Ready(Err(e)), None) => Poll::Ready(Err(e)),
(Poll::Ready(Ok(())), None) => Poll::Ready(Ok(None)),
}
}
}