Skip to content

Commit

Permalink
Create UseFuture struct
Browse files Browse the repository at this point in the history
  • Loading branch information
matthunz committed Nov 24, 2023
1 parent dc70f41 commit b3f116b
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 75 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn counter(initial_value: i32) -> impl Composable {
}
});

Debugger::new(count)
dbg!(count);
}

fn app() -> impl Composable {
Expand Down
4 changes: 2 additions & 2 deletions examples/app.rs → examples/counter.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -12,7 +12,7 @@ fn counter(initial_value: i32) -> impl Composable {
}
});

Debugger::new(count)
dbg!(count);
}

fn app() -> impl Composable {
Expand Down
21 changes: 3 additions & 18 deletions src/composable.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::BuildContext;
use std::fmt;

pub trait Composable {
type State: 'static;
Expand Down Expand Up @@ -37,24 +36,10 @@ impl<A: Composable, B: Composable> Composable for (A, B) {
}
}

pub struct Debugger<T> {
value: T,
}

impl<T> Debugger<T> {
pub fn new(value: T) -> Self {
Self { value }
}
}

impl<T: fmt::Debug> Composable for Debugger<T> {
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) {}
}
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down
51 changes: 38 additions & 13 deletions src/use_future.rs
Original file line number Diff line number Diff line change
@@ -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: Future + 'static>(f: impl FnOnce() -> F) {
use_hook(|| {
pub fn use_future<F>(f: impl FnOnce() -> F) -> UseFuture<F::Output>
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<T> {
handle: UseHook<JoinHandle<T>>,
}

impl<T: 'static> UseFuture<T> {
pub fn abort(&self) {
self.handle.get().abort()
}
}

impl<T> Clone for UseFuture<T> {
fn clone(&self) -> Self {
*self
}
}

impl<T> Copy for UseFuture<T> {}
62 changes: 59 additions & 3 deletions src/use_hook.rs
Original file line number Diff line number Diff line change
@@ -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<T: 'static>(make_value: impl FnOnce() -> T) -> Rc<RefCell<dyn Any>> {
pub fn use_hook<T: 'static>(make_value: impl FnOnce() -> T) -> UseHook<T> {
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<T: 'static>(make_value: impl FnOnce() -> T) -> Rc<RefCell<dyn Any>> {
let cx = LocalContext::current();
let mut inner = cx.inner.borrow_mut();
let mut hooks = inner.hooks.borrow_mut();
Expand All @@ -20,3 +46,33 @@ pub fn use_hook<T: 'static>(make_value: impl FnOnce() -> T) -> Rc<RefCell<dyn An

value
}

pub struct UseHook<T> {
pub key: DefaultKey,
_marker: PhantomData<T>,
}

impl<T> Clone for UseHook<T> {
fn clone(&self) -> Self {
*self
}
}

impl<T> Copy for UseHook<T> {}

impl<T: 'static> UseHook<T> {
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()
}
}
52 changes: 18 additions & 34 deletions src/use_state.rs
Original file line number Diff line number Diff line change
@@ -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<T: 'static>(make_value: impl FnOnce() -> T) -> State<T> {
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<T: 'static>(make_value: impl FnOnce() -> T) -> UseState<T> {
let hook = use_hook(make_value);
UseState { hook }
}

pub struct State<T> {
key: DefaultKey,
_marker: PhantomData<T>,
pub struct UseState<T> {
hook: UseHook<T>,
}

impl<T> Clone for State<T> {
impl<T> Clone for UseState<T> {
fn clone(&self) -> Self {
*self
}
}

impl<T> Copy for State<T> {}
impl<T> Copy for UseState<T> {}

impl<T: 'static> State<T> {
impl<T: 'static> UseState<T> {
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) }
Expand All @@ -53,7 +37,7 @@ impl<T: 'static> State<T> {
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
Expand All @@ -78,7 +62,7 @@ impl<T: 'static> State<T> {
}
}

impl<T> fmt::Debug for State<T>
impl<T> fmt::Debug for UseState<T>
where
T: fmt::Debug + 'static,
{
Expand All @@ -87,7 +71,7 @@ where
}
}

impl<T> AddAssign<T> for State<T>
impl<T> AddAssign<T> for UseState<T>
where
T: Add<Output = T> + Clone + 'static,
{
Expand Down

0 comments on commit b3f116b

Please sign in to comment.