Skip to content

Commit

Permalink
Create Scope::build, rebuild, and clear functions
Browse files Browse the repository at this point in the history
  • Loading branch information
matthunz committed Jan 26, 2024
1 parent 816fe37 commit bdb39a8
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 79 deletions.
111 changes: 66 additions & 45 deletions crates/concoct/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use slotmap::{DefaultKey, SlotMap};
use std::{
any::{Any, TypeId},
cell::{Cell, RefCell, UnsafeCell},
mem,
ops::DerefMut,
rc::Rc,
task::Waker,
Expand Down Expand Up @@ -74,6 +75,71 @@ impl<T, A> Scope<T, A> {
update: self.update.clone(),
}
}

/// Manually build a tree of views.
pub fn build(&self, mut view: impl View<T, A>) {
let node = Node::default();
let key = self.nodes.borrow_mut().insert(node.clone());
self.node.inner.borrow_mut().children.push(key);

let child_cx = Scope {
key,
parent: Some(self.key),
node,
update: self.update.clone(),
is_empty: Cell::new(false),
nodes: self.nodes.clone(),
contexts: self.contexts.clone(),
};

let body = view.body(&child_cx);
if !child_cx.is_empty.get() {
child_cx.build(body);
}
}

/// Manually rebuild a tree of views.
pub fn rebuild(&self, mut view: impl View<T, A>) {
for child_key in &self.node.inner.borrow().children {
let node = self.nodes.borrow().get(*child_key).cloned();
if let Some(node) = node {
node.inner.borrow_mut().hook_idx = 0;

let child_cx = Scope {
key: *child_key,
node,
parent: Some(self.key),
update: self.update.clone(),
is_empty: Cell::new(false),
nodes: self.nodes.clone(),
contexts: self.contexts.clone(),
};

let body = view.body(&child_cx);
if !child_cx.is_empty.get() {
child_cx.rebuild(body);
}
}
}
}

/// Remove all of this scope's children from the virtual dom.
pub fn clear(&self) {
let mut nodes_ref = self.nodes.borrow_mut();
let mut stack = Vec::new();
for child_key in &mem::take(&mut self.node.inner.borrow_mut().children) {
let child_node = nodes_ref[*child_key].clone();
stack.push((*child_key, child_node));
}

while let Some((key, node)) = stack.pop() {
nodes_ref.remove(key);
for child_key in &node.inner.borrow().children {
let child_node = nodes_ref[*child_key].clone();
stack.push((*child_key, child_node));
}
}
}
}

#[derive(Default)]
Expand All @@ -93,51 +159,6 @@ struct Channel<T> {
waker: Option<Waker>,
}

fn build_inner<T, A>(view: &mut impl View<T, A>, cx: &Scope<T, A>) {
let node = Node::default();
let key = cx.nodes.borrow_mut().insert(node.clone());
cx.node.inner.borrow_mut().children.push(key);

let child_cx = Scope {
key,
parent: Some(cx.key),
node,
update: cx.update.clone(),
is_empty: Cell::new(false),
nodes: cx.nodes.clone(),
contexts: cx.contexts.clone(),
};

let mut body = view.body(&child_cx);
if !child_cx.is_empty.get() {
build_inner(&mut body, &child_cx);
}
}

fn rebuild_inner<T, A>(view: &mut impl View<T, A>, cx: &Scope<T, A>) {
for child_key in &cx.node.inner.borrow().children {
let node = cx.nodes.borrow().get(*child_key).cloned();
if let Some(node) = node {
node.inner.borrow_mut().hook_idx = 0;

let child_cx = Scope {
key: *child_key,
node,
parent: Some(cx.key),
update: cx.update.clone(),
is_empty: Cell::new(false),
nodes: cx.nodes.clone(),
contexts: cx.contexts.clone(),
};

let mut body = view.body(&child_cx);
if !child_cx.is_empty.get() {
rebuild_inner(&mut body, &child_cx);
}
}
}
}

/// Run a view on a new virtual dom.
pub async fn run<T, V>(content: V)
where
Expand Down
12 changes: 6 additions & 6 deletions crates/concoct/src/vdom.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
use crate::{Channel, Node, Scope, View};
use slotmap::{DefaultKey, SlotMap};
use std::{
cell::{Cell, RefCell},
ops::DerefMut,
rc::Rc,
};

use slotmap::{DefaultKey, SlotMap};

use crate::{build_inner, rebuild_inner, Channel, Node, Scope, View};

/// Virtual DOM for a view.
pub struct VirtualDom<T, V> {
content: V,
Expand Down Expand Up @@ -56,7 +54,8 @@ impl<T, V> VirtualDom<T, V> {
nodes: self.nodes.clone(),
contexts: Default::default(),
};
build_inner(&mut self.content, &cx)

cx.build(&mut self.content)
}

/// Rebuild the content from the last build
Expand Down Expand Up @@ -102,7 +101,8 @@ impl<T, V> VirtualDom<T, V> {
nodes: self.nodes.clone(),
contexts: Default::default(),
};
rebuild_inner(&mut self.content, &cx);

cx.rebuild(&mut self.content)
}

std::task::Poll::Pending
Expand Down
6 changes: 3 additions & 3 deletions crates/concoct/src/view/adapt.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{build_inner, rebuild_inner, Scope, View};
use crate::{Scope, View};
use std::{cell::RefCell, marker::PhantomData, rc::Rc};

/// Adapt a view's state to a different one.
Expand Down Expand Up @@ -52,9 +52,9 @@ where
};

if cx.node.inner.borrow().children.is_empty() {
build_inner(&mut self.view, &child_cx);
child_cx.build(&mut self.view);
} else {
rebuild_inner(&mut self.view, &child_cx);
child_cx.rebuild(&mut self.view);
}
}
}
6 changes: 3 additions & 3 deletions crates/concoct/src/view/memo.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{build_inner, hook::use_ref, rebuild_inner, Scope, View};
use crate::{hook::use_ref, Scope, View};
use rustc_hash::FxHasher;
use std::hash::{Hash, Hasher};

Expand Down Expand Up @@ -32,9 +32,9 @@ where
*last_hash = self.hash;

if cx.node.inner.borrow().children.is_empty() {
build_inner(&mut self.view, &cx);
cx.build(&mut self.view)
} else {
rebuild_inner(&mut self.view, &cx);
cx.rebuild(&mut self.view)
}
}
}
Expand Down
28 changes: 6 additions & 22 deletions crates/concoct/src/view/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! Viewable components.

use crate::hook::use_ref;
use crate::{build_inner, hook::use_context, rebuild_inner, Scope};
use std::mem;
use crate::{hook::use_context, Scope};
use std::{cell::Cell, rc::Rc};

mod adapt;
Expand Down Expand Up @@ -38,29 +37,14 @@ impl<T, A, V: View<T, A>> View<T, A> for Option<V> {

if let Some(view) = self {
if *is_some {
rebuild_inner(view, cx);
cx.rebuild(view);
} else {
build_inner(view, cx);
cx.build(view);
}
*is_some = true;
} else if *is_some {
*is_some = false;

let mut nodes_ref = cx.nodes.borrow_mut();

let mut stack = Vec::new();
for child_key in &mem::take(&mut cx.node.inner.borrow_mut().children) {
let child_node = nodes_ref[*child_key].clone();
stack.push((*child_key, child_node));
}

while let Some((key, node)) = stack.pop() {
nodes_ref.remove(key);
for child_key in &node.inner.borrow().children {
let child_node = nodes_ref[*child_key].clone();
stack.push((*child_key, child_node));
}
}
cx.clear()
}
}
}
Expand All @@ -70,7 +54,7 @@ macro_rules! impl_view_for_tuple {
impl<T, A, $($t: View<T, A>),*> View<T, A> for ($($t),*) {
fn body(&mut self, cx: &Scope<T, A>) -> impl View<T, A> {
if cx.node.inner.borrow().children.is_empty() {
$( build_inner(&mut self.$idx, cx); )*
$( cx.build(&mut self.$idx); )*
} else {
$( {
let key = cx.node.inner.borrow().children[$idx];
Expand All @@ -89,7 +73,7 @@ macro_rules! impl_view_for_tuple {

let mut body = self.$idx.body(&cx);
if !cx.is_empty.get() {
rebuild_inner(&mut body, &cx);
cx.rebuild(&mut body);
}
} )*
}
Expand Down

0 comments on commit bdb39a8

Please sign in to comment.