wip: clean up some things
This commit is contained in:
1 parent
ba26b1001a
commit
3b166c9edd
64 files changed
+540
-599
No files matched your search
@@ -3,7 +3,7 @@
|
||||
//! This module provides support for a type called `LazyNodes` which is a micro-heap located on the stack to make calls
|
||||
//! to `rsx!` more efficient.
|
||||
//!
|
||||
//! To support returning rsx! from branches in match statements, we need to use dynamic dispatch on [`NodeFactory`] closures.
|
||||
//! To support returning rsx! from branches in match statements, we need to use dynamic dispatch on [`ScopeState`] closures.
|
||||
//!
|
||||
//! This can be done either through boxing directly, or by using dynamic-sized-types and a custom allocator. In our case,
|
||||
//! we build a tiny alloactor in the stack and allocate the closure into that.
|
||||
@@ -27,13 +27,11 @@ pub struct LazyNodes<'a, 'b> {
|
||||
inner: StackNodeStorage<'a, 'b>,
|
||||
}
|
||||
|
||||
pub type NodeFactory<'a> = &'a ScopeState;
|
||||
|
||||
type StackHeapSize = [usize; 16];
|
||||
|
||||
enum StackNodeStorage<'a, 'b> {
|
||||
Stack(LazyStack),
|
||||
Heap(Box<dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> + 'b>),
|
||||
Heap(Box<dyn FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>> + 'b>),
|
||||
}
|
||||
|
||||
impl<'a, 'b> LazyNodes<'a, 'b> {
|
||||
@@ -42,11 +40,11 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
|
||||
/// If the closure cannot fit into the stack allocation (16 bytes), then it
|
||||
/// is placed on the heap. Most closures will fit into the stack, and is
|
||||
/// the most optimal way to use the creation function.
|
||||
pub fn new(val: impl FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b) -> Self {
|
||||
pub fn new(val: impl FnOnce(&'a ScopeState) -> VNode<'a> + 'b) -> Self {
|
||||
// there's no way to call FnOnce without a box, so we need to store it in a slot and use static dispatch
|
||||
let mut slot = Some(val);
|
||||
|
||||
let val = move |fac: Option<NodeFactory<'a>>| {
|
||||
let val = move |fac: Option<&'a ScopeState>| {
|
||||
fac.map(
|
||||
slot.take()
|
||||
.expect("LazyNodes closure to be called only once"),
|
||||
@@ -67,13 +65,13 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
|
||||
/// Create a new [`LazyNodes`] closure, but force it onto the heap.
|
||||
pub fn new_boxed<F>(inner: F) -> Self
|
||||
where
|
||||
F: FnOnce(NodeFactory<'a>) -> VNode<'a> + 'b,
|
||||
F: FnOnce(&'a ScopeState) -> VNode<'a> + 'b,
|
||||
{
|
||||
// there's no way to call FnOnce without a box, so we need to store it in a slot and use static dispatch
|
||||
let mut slot = Some(inner);
|
||||
|
||||
Self {
|
||||
inner: StackNodeStorage::Heap(Box::new(move |fac: Option<NodeFactory<'a>>| {
|
||||
inner: StackNodeStorage::Heap(Box::new(move |fac: Option<&'a ScopeState>| {
|
||||
fac.map(
|
||||
slot.take()
|
||||
.expect("LazyNodes closure to be called only once"),
|
||||
@@ -84,9 +82,9 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
|
||||
|
||||
unsafe fn new_inner<F>(val: F) -> Self
|
||||
where
|
||||
F: FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> + 'b,
|
||||
F: FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>> + 'b,
|
||||
{
|
||||
let mut ptr: *const _ = &val as &dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>>;
|
||||
let mut ptr: *const _ = &val as &dyn FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>>;
|
||||
|
||||
assert_eq!(
|
||||
ptr as *const u8, &val as *const _ as *const u8,
|
||||
@@ -162,12 +160,10 @@ impl<'a, 'b> LazyNodes<'a, 'b> {
|
||||
/// ```rust, ignore
|
||||
/// let f = LazyNodes::new(move |f| f.element("div", [], [], [] None));
|
||||
///
|
||||
/// let fac = NodeFactory::new(&cx);
|
||||
///
|
||||
/// let node = f.call(cac);
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn call(self, f: NodeFactory<'a>) -> VNode<'a> {
|
||||
pub fn call(self, f: &'a ScopeState) -> VNode<'a> {
|
||||
match self.inner {
|
||||
StackNodeStorage::Heap(mut lazy) => {
|
||||
lazy(Some(f)).expect("Closure should not be called twice")
|
||||
@@ -184,18 +180,18 @@ struct LazyStack {
|
||||
}
|
||||
|
||||
impl LazyStack {
|
||||
fn call<'a>(&mut self, f: NodeFactory<'a>) -> VNode<'a> {
|
||||
fn call<'a>(&mut self, f: &'a ScopeState) -> VNode<'a> {
|
||||
let LazyStack { buf, .. } = self;
|
||||
let data = buf.as_ref();
|
||||
|
||||
let info_size =
|
||||
mem::size_of::<*mut dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>>>()
|
||||
mem::size_of::<*mut dyn FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>>>()
|
||||
/ mem::size_of::<usize>()
|
||||
- 1;
|
||||
|
||||
let info_ofs = data.len() - info_size;
|
||||
|
||||
let g: *mut dyn FnMut(Option<NodeFactory<'a>>) -> Option<VNode<'a>> =
|
||||
let g: *mut dyn FnMut(Option<&'a ScopeState>) -> Option<VNode<'a>> =
|
||||
unsafe { make_fat_ptr(data[..].as_ptr() as usize, &data[info_ofs..]) };
|
||||
|
||||
self.dropped = true;
|
||||
@@ -210,14 +206,14 @@ impl Drop for LazyStack {
|
||||
let LazyStack { buf, .. } = self;
|
||||
let data = buf.as_ref();
|
||||
|
||||
let info_size = mem::size_of::<
|
||||
*mut dyn FnMut(Option<NodeFactory<'_>>) -> Option<VNode<'_>>,
|
||||
>() / mem::size_of::<usize>()
|
||||
- 1;
|
||||
let info_size =
|
||||
mem::size_of::<*mut dyn FnMut(Option<&ScopeState>) -> Option<VNode<'_>>>()
|
||||
/ mem::size_of::<usize>()
|
||||
- 1;
|
||||
|
||||
let info_ofs = data.len() - info_size;
|
||||
|
||||
let g: *mut dyn FnMut(Option<NodeFactory<'_>>) -> Option<VNode<'_>> =
|
||||
let g: *mut dyn FnMut(Option<&ScopeState>) -> Option<VNode<'_>> =
|
||||
unsafe { make_fat_ptr(data[..].as_ptr() as usize, &data[info_ofs..]) };
|
||||
|
||||
self.dropped = true;
|
||||
@@ -252,73 +248,3 @@ unsafe fn make_fat_ptr<T: ?Sized>(data_ptr: usize, meta_vals: &[usize]) -> *mut
|
||||
fn round_to_words(len: usize) -> usize {
|
||||
(len + mem::size_of::<usize>() - 1) / mem::size_of::<usize>()
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use crate::innerlude::{Element, Scope, VirtualDom};
|
||||
|
||||
// #[test]
|
||||
// fn it_works() {
|
||||
// fn app(cx: Scope<()>) -> Element {
|
||||
// cx.render(LazyNodes::new(|f| f.text(format_args!("hello world!"))))
|
||||
// }
|
||||
|
||||
// let mut dom = VirtualDom::new(app);
|
||||
// dom.rebuild();
|
||||
|
||||
// let g = dom.base_scope().root_node();
|
||||
// dbg!(g);
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn it_drops() {
|
||||
// use std::rc::Rc;
|
||||
|
||||
// struct AppProps {
|
||||
// inner: Rc<i32>,
|
||||
// }
|
||||
|
||||
// fn app(cx: Scope<AppProps>) -> Element {
|
||||
// struct DropInner {
|
||||
// id: i32,
|
||||
// }
|
||||
// impl Drop for DropInner {
|
||||
// fn drop(&mut self) {
|
||||
// eprintln!("dropping inner");
|
||||
// }
|
||||
// }
|
||||
|
||||
// let caller = {
|
||||
// let it = (0..10).map(|i| {
|
||||
// let val = cx.props.inner.clone();
|
||||
// LazyNodes::new(move |f| {
|
||||
// eprintln!("hell closure");
|
||||
// let inner = DropInner { id: i };
|
||||
// f.text(format_args!("hello world {:?}, {:?}", inner.id, val))
|
||||
// })
|
||||
// });
|
||||
|
||||
// LazyNodes::new(|f| {
|
||||
// eprintln!("main closure");
|
||||
// f.fragment_from_iter(it)
|
||||
// })
|
||||
// };
|
||||
|
||||
// cx.render(caller)
|
||||
// }
|
||||
|
||||
// let inner = Rc::new(0);
|
||||
// let mut dom = VirtualDom::new_with_props(
|
||||
// app,
|
||||
// AppProps {
|
||||
// inner: inner.clone(),
|
||||
// },
|
||||
// );
|
||||
// dom.rebuild();
|
||||
|
||||
// drop(dom);
|
||||
|
||||
// assert_eq!(Rc::strong_count(&inner), 1);
|
||||
// }
|
||||
// }
|
||||
Reference in new issue
Block a user