1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use dioxus_core::{ScopeState, TaskId};
use std::future::Future;
use std::{cell::Cell, rc::Rc};
/*



let g = use_coroutine(&cx, || {
    // clone the items in
    async move {

    }
})



*/
pub fn use_coroutine<'a, F>(
    cx: &'a ScopeState,
    create_future: impl FnOnce() -> F,
) -> CoroutineHandle<'a>
where
    F: Future<Output = ()> + 'static,
{
    let state = cx.use_hook(move |_| {
        let f = create_future();
        let id = cx.push_future(f);
        State {
                running: Default::default(),
                _id: id
                // pending_fut: Default::default(),
                // running_fut: Default::default(),
            }
    });

    // state.pending_fut.set(Some(Box::pin(f)));

    // if let Some(fut) = state.running_fut.as_mut() {
    //     cx.push_future(fut);
    // }

    // if let Some(fut) = state.running_fut.take() {
    // state.running.set(true);
    // fut.resume();
    // }

    // let submit: Box<dyn FnOnce() + 'a> = Box::new(move || {
    //     let g = async move {
    //         running.set(true);
    //         create_future().await;
    //         running.set(false);
    //     };
    //     let p: Pin<Box<dyn Future<Output = ()>>> = Box::pin(g);
    //     fut_slot
    //         .borrow_mut()
    //         .replace(unsafe { std::mem::transmute(p) });
    // });

    // let submit = unsafe { std::mem::transmute(submit) };
    // state.submit.get_mut().replace(submit);

    // if state.running.get() {
    //     // let mut fut = state.fut.borrow_mut();
    //     // cx.push_task(|| fut.as_mut().unwrap().as_mut());
    // } else {
    //     // make sure to drop the old future
    //     if let Some(fut) = state.fut.borrow_mut().take() {
    //         drop(fut);
    //     }
    // }
    CoroutineHandle { cx, inner: state }
}

struct State {
    running: Rc<Cell<bool>>,
    _id: TaskId,
    // the way this is structure, you can toggle the coroutine without re-rendering the comppnent
    // this means every render *generates* the future, which is a bit of a waste
    // todo: allocate pending futures in the bump allocator and then have a true promotion
    // pending_fut: Cell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>,
    // running_fut: Option<Pin<Box<dyn Future<Output = ()> + 'static>>>,
    // running_fut: Rc<RefCell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>>
}

pub struct CoroutineHandle<'a> {
    cx: &'a ScopeState,
    inner: &'a State,
}

impl Clone for CoroutineHandle<'_> {
    fn clone(&self) -> Self {
        CoroutineHandle {
            cx: self.cx,
            inner: self.inner,
        }
    }
}
impl Copy for CoroutineHandle<'_> {}

impl<'a> CoroutineHandle<'a> {
    pub fn start(&self) {
        if self.is_running() {
            return;
        }

        // if let Some(submit) = self.inner.pending_fut.take() {
        // submit();
        // let inner = self.inner;
        // self.cx.push_task(submit());
        // }
    }

    pub fn is_running(&self) -> bool {
        self.inner.running.get()
    }

    pub fn resume(&self) {
        // self.cx.push_task(fut)
    }

    pub fn stop(&self) {}

    pub fn restart(&self) {}
}