diff --git a/README.md b/README.md index 6ad7ef86..3e747722 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ fn counter(initial_value: i32) -> impl Composable { } }); - Debugger::new(count) + dbg!(count); } fn app() -> impl Composable { diff --git a/examples/app.rs b/examples/counter.rs similarity index 84% rename from examples/app.rs rename to examples/counter.rs index 52a63a7f..f977c1a8 100644 --- a/examples/app.rs +++ b/examples/counter.rs @@ -1,4 +1,4 @@ -use concoct::{use_future, use_state, Composable, Composition, Debugger}; +use concoct::{use_future, use_state, Composable, Composition}; use std::time::Duration; use tokio::time; @@ -12,7 +12,7 @@ fn counter(initial_value: i32) -> impl Composable { } }); - Debugger::new(count) + dbg!(count); } fn app() -> impl Composable { diff --git a/src/composable.rs b/src/composable.rs index fcddcf1d..358245c1 100644 --- a/src/composable.rs +++ b/src/composable.rs @@ -1,5 +1,4 @@ use crate::BuildContext; -use std::fmt; pub trait Composable { type State: 'static; @@ -37,24 +36,10 @@ impl Composable for (A, B) { } } -pub struct Debugger { - value: T, -} - -impl Debugger { - pub fn new(value: T) -> Self { - Self { value } - } -} - -impl Composable for Debugger { +impl Composable for () { type State = (); - fn build(&mut self, _cx: &mut BuildContext) -> Self::State { - dbg!(&self.value); - } + fn build(&mut self, _cx: &mut BuildContext) -> Self::State {} - fn rebuild(&mut self, _state: &mut Self::State) { - dbg!(&self.value); - } + fn rebuild(&mut self, _state: &mut Self::State) {} } diff --git a/src/lib.rs b/src/lib.rs index e9a1029a..3ab50c1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ mod any_composable; pub use any_composable::AnyComposable; mod composable; -pub use composable::{Composable, Debugger}; +pub use composable::Composable; mod composition; pub use composition::Composition; @@ -15,13 +15,13 @@ mod node; pub use node::Node; mod use_hook; -pub use use_hook::use_hook; +pub use use_hook::{use_hook, UseHook}; mod use_future; -pub use use_future::use_future; +pub use use_future::{use_future, UseFuture}; mod use_state; -pub use use_state::{use_state, State}; +pub use use_state::{use_state, UseState}; #[derive(Default)] struct GlobalContext { diff --git a/src/use_future.rs b/src/use_future.rs index 207bd138..da25063b 100644 --- a/src/use_future.rs +++ b/src/use_future.rs @@ -1,18 +1,43 @@ -use crate::{use_hook, TASK_CONTEXT}; +use crate::{use_hook, UseHook, TASK_CONTEXT}; use futures::Future; -use tokio::task; +use tokio::task::{self, JoinHandle}; -pub fn use_future(f: impl FnOnce() -> F) { - use_hook(|| { +pub fn use_future(f: impl FnOnce() -> F) -> UseFuture +where + F: Future + 'static, +{ + let handle = use_hook(|| { let future = f(); - TASK_CONTEXT.try_with(|cx| { - let guard = cx.borrow_mut(); - let cx = guard.as_ref().unwrap(); - let tx = cx.tx.clone(); - task::spawn_local(async move { - future.await; - tx.send(Box::new(())).unwrap(); - }); - }) + TASK_CONTEXT + .try_with(|cx| { + let guard = cx.borrow_mut(); + let cx = guard.as_ref().unwrap(); + let tx = cx.tx.clone(); + task::spawn_local(async move { + let output = future.await; + tx.send(Box::new(())).unwrap(); + output + }) + }) + .unwrap() }); + UseFuture { handle } } + +pub struct UseFuture { + handle: UseHook>, +} + +impl UseFuture { + pub fn abort(&self) { + self.handle.get().abort() + } +} + +impl Clone for UseFuture { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for UseFuture {} diff --git a/src/use_hook.rs b/src/use_hook.rs index 4653f918..1c7a9e99 100644 --- a/src/use_hook.rs +++ b/src/use_hook.rs @@ -1,7 +1,33 @@ -use crate::LocalContext; -use std::{any::Any, cell::RefCell, rc::Rc}; +use crate::{LocalContext, GLOBAL_CONTEXT}; +use slotmap::DefaultKey; +use std::{ + any::Any, + cell::{Ref, RefCell}, + marker::PhantomData, + mem, + rc::Rc, +}; -pub fn use_hook(make_value: impl FnOnce() -> T) -> Rc> { +pub fn use_hook(make_value: impl FnOnce() -> T) -> UseHook { + let rc = use_hook_value(|| { + GLOBAL_CONTEXT + .try_with(|cx| { + cx.borrow_mut() + .values + .insert(Rc::new(RefCell::new(make_value()))) + }) + .unwrap() + }); + let guard = rc.borrow(); + let key: &DefaultKey = guard.downcast_ref().unwrap(); + + UseHook { + key: *key, + _marker: PhantomData, + } +} + +pub fn use_hook_value(make_value: impl FnOnce() -> T) -> Rc> { let cx = LocalContext::current(); let mut inner = cx.inner.borrow_mut(); let mut hooks = inner.hooks.borrow_mut(); @@ -20,3 +46,33 @@ pub fn use_hook(make_value: impl FnOnce() -> T) -> Rc { + pub key: DefaultKey, + _marker: PhantomData, +} + +impl Clone for UseHook { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for UseHook {} + +impl UseHook { + pub fn get(self) -> Ref<'static, T> { + let rc = GLOBAL_CONTEXT + .try_with(|cx| cx.borrow_mut().values[self.key].clone()) + .unwrap(); + let output: Ref<'_, T> = Ref::map(rc.borrow(), |value| value.downcast_ref().unwrap()); + unsafe { mem::transmute(output) } + } + + pub fn cloned(self) -> T + where + T: Clone, + { + self.get().clone() + } +} diff --git a/src/use_state.rs b/src/use_state.rs index a6ac39dc..4e82e131 100644 --- a/src/use_state.rs +++ b/src/use_state.rs @@ -1,50 +1,34 @@ -use crate::{use_hook, GLOBAL_CONTEXT, TASK_CONTEXT}; -use slotmap::DefaultKey; +use crate::{ + use_hook::{use_hook, UseHook}, + GLOBAL_CONTEXT, TASK_CONTEXT, +}; use std::{ - cell::{Ref, RefCell}, - fmt, - marker::PhantomData, - mem, + cell::Ref, + fmt, mem, ops::{Add, AddAssign}, - rc::Rc, }; -pub fn use_state(make_value: impl FnOnce() -> T) -> State { - let rc = use_hook(|| { - GLOBAL_CONTEXT - .try_with(|cx| { - cx.borrow_mut() - .values - .insert(Rc::new(RefCell::new(make_value()))) - }) - .unwrap() - }); - let guard = rc.borrow(); - let key: &DefaultKey = guard.downcast_ref().unwrap(); - - State { - key: *key, - _marker: PhantomData, - } +pub fn use_state(make_value: impl FnOnce() -> T) -> UseState { + let hook = use_hook(make_value); + UseState { hook } } -pub struct State { - key: DefaultKey, - _marker: PhantomData, +pub struct UseState { + hook: UseHook, } -impl Clone for State { +impl Clone for UseState { fn clone(&self) -> Self { *self } } -impl Copy for State {} +impl Copy for UseState {} -impl State { +impl UseState { pub fn get(self) -> Ref<'static, T> { let rc = GLOBAL_CONTEXT - .try_with(|cx| cx.borrow_mut().values[self.key].clone()) + .try_with(|cx| cx.borrow_mut().values[self.hook.key].clone()) .unwrap(); let output: Ref<'_, T> = Ref::map(rc.borrow(), |value| value.downcast_ref().unwrap()); unsafe { mem::transmute(output) } @@ -53,7 +37,7 @@ impl State { pub fn set(&self, value: T) { GLOBAL_CONTEXT .try_with(|cx| { - *cx.borrow_mut().values[self.key] + *cx.borrow_mut().values[self.hook.key] .borrow_mut() .downcast_mut() .unwrap() = value @@ -78,7 +62,7 @@ impl State { } } -impl fmt::Debug for State +impl fmt::Debug for UseState where T: fmt::Debug + 'static, { @@ -87,7 +71,7 @@ where } } -impl AddAssign for State +impl AddAssign for UseState where T: Add + Clone + 'static, {