use std::{
future::Ready,
pin::Pin,
task::{Context, Poll},
};
use pin_project_lite::pin_project;
use topcoat_core::error::Result;
use super::yielder::{DriveFuture, Yield, poll_body};
use crate::{View, ViewFirst, ViewSwap};
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_body(this.body, cx) {
(Poll::Pending, Some(Yield::First(first))) => Poll::Ready(Ok(first)),
(Poll::Pending, None) => Poll::Pending,
(Poll::Pending, Some(Yield::Swap(_))) => {
panic!("move view future yielded a swap before its first content")
}
(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_body(this.body, cx) {
(Poll::Pending, Some(Yield::Swap(swap))) => Poll::Ready(Ok(Some(swap))),
(Poll::Pending, None) => Poll::Pending,
(Poll::Pending, Some(Yield::First(_))) => {
panic!("move view future yielded first content twice")
}
(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)),
}
}
}