Skip to content

Commit

Permalink
Store pointers to the composition
Browse files Browse the repository at this point in the history
  • Loading branch information
matthunz committed Dec 5, 2024
1 parent f6341ac commit 9db03b4
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 5 deletions.
2 changes: 2 additions & 0 deletions examples/core/composer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ fn main() {
composer.try_compose().unwrap();

assert_eq!(composer.try_compose(), Err(TryComposeError::Pending));

dbg!(composer);
}
40 changes: 35 additions & 5 deletions src/compose/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use crate::{data::Data, use_context, use_ref, Scope, ScopeData, ScopeState};
use crate::{
composer::{Node, Runtime},
data::Data,
use_context, use_ref, Scope, ScopeData, ScopeState,
};
use alloc::borrow::Cow;
use core::{
any::TypeId,
Expand Down Expand Up @@ -207,6 +211,8 @@ pub(crate) trait AnyCompose {

/// Safety: The caller must ensure `&self` is valid for the lifetime of `state`.
unsafe fn any_compose(&self, state: &ScopeData);

fn name(&self) -> Option<Cow<'static, str>>;
}

impl<C> AnyCompose for C
Expand All @@ -226,6 +232,30 @@ where
}

unsafe fn any_compose(&self, state: &ScopeData) {
if typeid::of::<C>() == typeid::of::<()>() {
return;
}

let ptr = state as *const ScopeData;
let ptr = unsafe { mem::transmute(ptr) };
let rt = Runtime::current();
let mut scopes = rt.nodes.borrow_mut();

let compose = self as *const dyn AnyCompose;
let compose = unsafe { mem::transmute(compose) };
let key = scopes.insert(Node {
compose: Some(compose),
scope: ptr,
children: Vec::new(),
});
scopes
.get_mut(rt.parent_key.get())
.unwrap()
.children
.push(key);
drop(scopes);
rt.parent_key.set(key);

// Reset the hook index.
state.hook_idx.set(0);

Expand All @@ -243,10 +273,6 @@ where
// Safety: This cell is only accessed by this composable.
let cell = unsafe { &mut *cell.get() };

if typeid::of::<C>() == typeid::of::<()>() {
return;
}

// Scope for this composable's content.
let child_state = use_ref(&cx, ScopeData::default);

Expand Down Expand Up @@ -291,4 +317,8 @@ where
let child = cell.as_mut().unwrap();
(*child).any_compose(child_state);
}

fn name(&self) -> Option<Cow<'static, str>> {
C::name()
}
}
64 changes: 64 additions & 0 deletions src/composer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use core::{
any::TypeId,
cell::{Cell, RefCell},
error::Error,
fmt,
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
Expand All @@ -19,6 +20,12 @@ use tokio::sync::RwLock;

type RuntimeFuture = Pin<Box<dyn Future<Output = ()>>>;

pub(crate) struct Node {
pub(crate) compose: Option<*const dyn AnyCompose>,
pub(crate) scope: *const ScopeData<'static>,
pub(crate) children: Vec<DefaultKey>,
}

/// Runtime for a [`Composer`].
#[derive(Clone)]
pub struct Runtime {
Expand All @@ -36,6 +43,12 @@ pub struct Runtime {
pub(crate) lock: Arc<RwLock<()>>,

pub(crate) waker: RefCell<Option<Waker>>,

pub(crate) nodes: Rc<RefCell<SlotMap<DefaultKey, Node>>>,

pub(crate) parent_key: Rc<Cell<DefaultKey>>,

pub(crate) root: DefaultKey,
}

impl Runtime {
Expand Down Expand Up @@ -132,6 +145,14 @@ impl Composer {
let update_queue = Rc::new(SegQueue::new());

let scope_data = ScopeData::default();

let mut nodes = SlotMap::new();
let root_key = nodes.insert(Node {
compose: None,
scope: core::ptr::null(),
children: Vec::new(),
});

Self {
compose: Box::new(content),
scope_state: Box::new(scope_data),
Expand All @@ -142,6 +163,9 @@ impl Composer {
waker: RefCell::new(None),
#[cfg(feature = "executor")]
lock,
nodes: Rc::new(RefCell::new(nodes)),
parent_key: Rc::new(Cell::new(root_key)),
root: root_key,
},
task_queue,
update_queue,
Expand Down Expand Up @@ -221,6 +245,46 @@ impl Composer {
}
}

impl fmt::Debug for Composer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Composer")
.field(
"nodes",
&Debugger {
nodes: &self.rt.nodes.borrow(),
key: self.rt.root,
},
)
.finish()
}
}

struct Debugger<'a> {
nodes: &'a SlotMap<DefaultKey, Node>,
key: DefaultKey,
}

impl fmt::Debug for Debugger<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let node = &self.nodes[self.key];
let name = node
.compose
.and_then(|compose| unsafe { (*compose).name() })
.unwrap_or_default();

let mut dbg_tuple = f.debug_tuple(&name);

for child in &node.children {
dbg_tuple.field(&Debugger {
nodes: self.nodes,
key: *child,
});
}

dbg_tuple.finish()
}
}

#[cfg(all(test, feature = "rt"))]
mod tests {
use crate::{
Expand Down

0 comments on commit 9db03b4

Please sign in to comment.