diff --git a/packages/hooks/src/use_future.rs b/packages/hooks/src/use_future.rs index c9596d295..ff6ae35f9 100644 --- a/packages/hooks/src/use_future.rs +++ b/packages/hooks/src/use_future.rs @@ -24,7 +24,7 @@ where flush_sync().await; state.set(UseFutureState::Pending); fut.await; - state.set(UseFutureState::Complete); + state.set(UseFutureState::Ready); }) }); @@ -70,7 +70,7 @@ pub enum UseFutureState { Paused, /// The future has completed - Complete, + Ready, } impl UseFuture { @@ -118,7 +118,7 @@ impl UseFuture { pub fn finished(&self) -> bool { matches!( self.state.peek().clone(), - UseFutureState::Complete | UseFutureState::Stopped + UseFutureState::Ready | UseFutureState::Stopped ) } diff --git a/packages/hooks/src/use_resource.rs b/packages/hooks/src/use_resource.rs index 92c81bbe4..c25aa947b 100644 --- a/packages/hooks/src/use_resource.rs +++ b/packages/hooks/src/use_resource.rs @@ -1,8 +1,8 @@ #![allow(missing_docs)] -use crate::{use_callback, use_signal}; +use crate::{use_callback, use_signal, UseCallback}; use dioxus_core::{ - prelude::{flush_sync, spawn, suspend, use_hook}, + prelude::{spawn, suspend, use_hook}, Task, }; use dioxus_signals::*; @@ -59,7 +59,12 @@ where }) }); - Resource { task, value, state } + Resource { + task, + value, + state, + callback: cb, + } } #[allow(unused)] @@ -67,6 +72,24 @@ pub struct Resource { value: Signal>>, task: Signal, state: Signal, + callback: UseCallback, +} + +/// A signal that represents the state of a future +// we might add more states (panicked, etc) +#[derive(Clone, Copy, PartialEq, Hash, Eq, Debug)] +pub enum UseResourceState { + /// The future is still running + Pending, + + /// The future has been forcefully stopped + Stopped, + + /// The future has been paused, tempoarily + Paused, + + /// The future has completed + Ready, } impl Resource { @@ -74,71 +97,62 @@ impl Resource { /// /// Will not cancel the previous future, but will ignore any values that it /// generates. - pub fn restart(&self) { - // self.needs_regen.set(true); - // (self.update)(); + pub fn restart(&mut self) { + self.task.write().cancel(); + let new_task = self.callback.call(); + self.task.set(new_task); } /// Forcefully cancel a future - pub fn cancel(&self) { - // if let Some(task) = self.task.take() { - // cx.remove_future(task); - // } + pub fn cancel(&mut self) { + self.state.set(UseResourceState::Stopped); + self.task.write().cancel(); } - // Manually set the value in the future slot without starting the future over - pub fn set(&mut self, new_value: T) { - // if let Some(task) = self.task.take() { - // cx.remove_future(task); - // } - // self.value.set(Some(new_value)); + /// Pause the future + pub fn pause(&mut self) { + self.state.set(UseResourceState::Paused); + self.task.write().pause(); } - /// Return any value, even old values if the future has not yet resolved. + /// Resume the future + pub fn resume(&mut self) { + if self.finished() { + return; + } + + self.state.set(UseResourceState::Pending); + self.task.write().resume(); + } + + /// Get a handle to the inner task backing this future + /// Modify the task through this handle will cause inconsistent state + pub fn task(&self) -> Task { + self.task.cloned() + } + + /// Is the future currently finished running? /// - /// If the future has never completed, the returned value will be `None`. - pub fn value(&self) -> Option> { - self.value.cloned().map(|sig| sig.into()) - } - - /// Get the ID of the future in Dioxus' internal scheduler - pub fn task(&self) -> Option { - todo!() - // self.task.get() + /// Reading this does not subscribe to the future's state + pub fn finished(&self) -> bool { + matches!( + self.state.peek().clone(), + UseResourceState::Ready | UseResourceState::Stopped + ) } /// Get the current state of the future. - pub fn state(&self) -> UseResourceState { - todo!() - // match (&self.task.get(), &self.value()) { - // // If we have a task and an existing value, we're reloading - // (Some(_), Some(val)) => UseResourceState::Reloading(val), - - // // no task, but value - we're done - // (None, Some(val)) => UseResourceState::Complete(val), - - // // no task, no value - something's wrong? return pending - // (None, None) => UseResourceState::Pending, - - // // Task, no value - we're still pending - // (Some(_), None) => UseResourceState::Pending, - // } + pub fn state(&self) -> ReadOnlySignal { + self.state.clone().into() } /// Wait for this async memo to resolve, returning the inner signal value /// If the value is pending, returns none and suspends the current component pub fn suspend(&self) -> Option> { - let out = self.value(); + let out = self.value.read().clone(); if out.is_none() { suspend(); } out.map(|sig| sig.into()) } } - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum UseResourceState { - Pending, - Ready, - Regenerating, // the old value -}