async_ui_core 0.1.0

Shared code for Async UI
Documentation
mod child;
use std::{
    future::Future,
    pin::Pin,
    rc::Rc,
    task::{Context, Poll},
};

use child::Child;
use pin_project_lite::pin_project;
use scoped_async_spawn::SpawnGuard;

use crate::{backend::BackendTrait, vnode::node_pass::PassVNode};

#[doc(hidden)]
pub mod __private_macro_only {
    pub use super::child::Child;
    pub use super::Fragment;

    #[macro_export]
    macro_rules! fragment {
        [$($ch:expr),*] => {
            $crate::__private_macro_only::Fragment::new_from_vec(::std::vec![
                $($crate::__private_macro_only::Child::new($ch)),*
            ])
        }
    }
}

pin_project! {
    pub struct Fragment<'c, B>
    where
        B: BackendTrait
    {
        children: Vec<Child<'c, B>>,
        mounted: bool,
        #[pin]
        guard: SpawnGuard<'c>,
    }
}
impl<'c, B> Default for Fragment<'c, B>
where
    B: BackendTrait,
{
    fn default() -> Self {
        Self::new_from_vec(Vec::new())
    }
}
impl<'c, B> Fragment<'c, B>
where
    B: BackendTrait,
{
    pub fn new_from_vec(children: Vec<Child<'c, B>>) -> Self {
        Self {
            children,
            mounted: false,
            guard: SpawnGuard::new(),
        }
    }
}

use std::future::IntoFuture;
macro_rules! impl_tuple_of_children {
    ($($arg:ident=$num:tt),*) => {
        impl<'c, B: BackendTrait, $($arg : IntoFuture<Output = ()> + 'c,)*> From<($($arg,)*)> for Fragment<'c, B> {
            #[allow(unused_variables)]
            fn from(source: ($($arg,)*)) -> Self {
                crate::fragment![
                    $(source.$num),*
                ]
            }
        }
    };
}
impl_tuple_of_children!();
impl_tuple_of_children!(A0 = 0);
impl_tuple_of_children!(A0 = 0, A1 = 1);
impl_tuple_of_children!(A0 = 0, A1 = 1, A2 = 2);
impl_tuple_of_children!(A0 = 0, A1 = 1, A2 = 2, A3 = 3);
impl_tuple_of_children!(A0 = 0, A1 = 1, A2 = 2, A3 = 3, A4 = 4);
impl_tuple_of_children!(A0 = 0, A1 = 1, A2 = 2, A3 = 3, A4 = 4, A5 = 5);
impl_tuple_of_children!(A0 = 0, A1 = 1, A2 = 2, A3 = 3, A4 = 4, A5 = 5, A6 = 6);
impl_tuple_of_children!(
    A0 = 0,
    A1 = 1,
    A2 = 2,
    A3 = 3,
    A4 = 4,
    A5 = 5,
    A6 = 6,
    A7 = 7
);
impl_tuple_of_children!(
    A0 = 0,
    A1 = 1,
    A2 = 2,
    A3 = 3,
    A4 = 4,
    A5 = 5,
    A6 = 6,
    A7 = 7,
    A8 = 8
);
impl_tuple_of_children!(
    A0 = 0,
    A1 = 1,
    A2 = 2,
    A3 = 3,
    A4 = 4,
    A5 = 5,
    A6 = 6,
    A7 = 7,
    A8 = 8,
    A9 = 9
);
impl_tuple_of_children!(
    A0 = 0,
    A1 = 1,
    A2 = 2,
    A3 = 3,
    A4 = 4,
    A5 = 5,
    A6 = 6,
    A7 = 7,
    A8 = 8,
    A9 = 9,
    A10 = 10
);
impl_tuple_of_children!(
    A0 = 0,
    A1 = 1,
    A2 = 2,
    A3 = 3,
    A4 = 4,
    A5 = 5,
    A6 = 6,
    A7 = 7,
    A8 = 8,
    A9 = 9,
    A10 = 10,
    A11 = 11
);

impl<'c, B> Future for Fragment<'c, B>
where
    B: BackendTrait,
{
    type Output = ();

    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut this = self.project();
        let parent_vnode = B::get_vnode_key().with(Clone::clone);
        if !*this.mounted {
            *this.mounted = true;
            if this.children.len() > 1 {
                this.children.iter_mut().enumerate().for_each(|(idx, ch)| {
                    let vnode = Rc::new(PassVNode::new(parent_vnode.clone(), idx).into());
                    ch.mount(vnode, this.guard.as_mut());
                });
            } else if let Some(ch) = this.children.first_mut() {
                ch.mount(parent_vnode, this.guard);
            }
        }
        Poll::Pending
    }
}