fix: messed up how lifetimes worked, need to render once per component
This commit is contained in:
1 parent
0e9d5fc530
commit
ba9e1dbb8f
33 files changed
+323
-184
No files matched your search
@@ -20,7 +20,7 @@ fn main() {
|
|||||||
dioxus::desktop::launch(App, |c| c);
|
dioxus::desktop::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn App((cx, props): Component<()>) -> Element {
|
fn App((cx, props): Scope<()>) -> Element {
|
||||||
let text: &mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f, |_| {});
|
let text: &mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f, |_| {});
|
||||||
|
|
||||||
let first = text.get_mut(0).unwrap();
|
let first = text.get_mut(0).unwrap();
|
||||||
@@ -43,7 +43,7 @@ impl<'a> Drop for C1Props<'a> {
|
|||||||
fn drop(&mut self) {}
|
fn drop(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Child1<'a>((cx, props): Component<'a, C1Props>) -> Element<'a> {
|
fn Child1<'a>((cx, props): Scope<'a, C1Props>) -> Element<'a> {
|
||||||
let (left, right) = props.text.split_once("=").unwrap();
|
let (left, right) = props.text.split_once("=").unwrap();
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
@@ -59,7 +59,7 @@ struct C2Props<'a> {
|
|||||||
text: &'a str,
|
text: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Child2<'a>((cx, props): Component<'a, C2Props>) -> Element<'a> {
|
fn Child2<'a>((cx, props): Scope<'a, C2Props>) -> Element<'a> {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
Child3 {
|
Child3 {
|
||||||
text: props.text
|
text: props.text
|
||||||
@@ -72,7 +72,7 @@ struct C3Props<'a> {
|
|||||||
text: &'a str,
|
text: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Child3<'a>((cx, props): Component<'a, C3Props>) -> Element<'a> {
|
fn Child3<'a>((cx, props): Scope<'a, C3Props>) -> Element<'a> {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div { "{props.text}"}
|
div { "{props.text}"}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ struct CalculatorKeyProps<'a> {
|
|||||||
onclick: &'a dyn Fn(MouseEvent),
|
onclick: &'a dyn Fn(MouseEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn CalculatorKey<'a>((cx, props): Component<'a, CalculatorKeyProps>) -> Element<'a> {
|
fn CalculatorKey<'a>((cx, props): Scope<'a, CalculatorKeyProps>) -> Element<'a> {
|
||||||
rsx!(cx, button {
|
rsx!(cx, button {
|
||||||
class: "calculator-key {props.name}"
|
class: "calculator-key {props.name}"
|
||||||
onclick: {props.onclick}
|
onclick: {props.onclick}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ struct ActionButtonProps<'a> {
|
|||||||
onclick: &'a dyn Fn(MouseEvent),
|
onclick: &'a dyn Fn(MouseEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ActionButton<'a>((cx, props): Component<'a, ActionButtonProps>) -> Element<'a> {
|
fn ActionButton<'a>((cx, props): Scope<'a, ActionButtonProps>) -> Element<'a> {
|
||||||
rsx!(cx, div { class: "col-sm-6 smallpad"
|
rsx!(cx, div { class: "col-sm-6 smallpad"
|
||||||
button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: {props.onclick},
|
button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: {props.onclick},
|
||||||
"{props.name}"
|
"{props.name}"
|
||||||
@@ -93,7 +93,7 @@ struct RowProps {
|
|||||||
row_id: usize,
|
row_id: usize,
|
||||||
label: Rc<str>,
|
label: Rc<str>,
|
||||||
}
|
}
|
||||||
fn Row((cx, props): Component<RowProps>) -> Element {
|
fn Row((cx, props): Scope<RowProps>) -> Element {
|
||||||
rsx!(cx, tr {
|
rsx!(cx, tr {
|
||||||
td { class:"col-md-1", "{props.row_id}" }
|
td { class:"col-md-1", "{props.row_id}" }
|
||||||
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ fn main() {
|
|||||||
dioxus::desktop::launch(App, |c| c);
|
dioxus::desktop::launch(App, |c| c);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn App((cx, props): Component<()>) -> Element {
|
fn App((cx, props): Scope<()>) -> Element {
|
||||||
cx.render(rsx! (
|
cx.render(rsx! (
|
||||||
div { "Hello, world!" }
|
div { "Hello, world!" }
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ struct CalculatorKeyProps<'a> {
|
|||||||
onclick: &'a dyn Fn(MouseEvent),
|
onclick: &'a dyn Fn(MouseEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn CalculatorKey<'a>((cx, props): Component<'a, CalculatorKeyProps>) -> Element<'a> {
|
fn CalculatorKey<'a>((cx, props): Scope<'a, CalculatorKeyProps>) -> Element<'a> {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
button {
|
button {
|
||||||
class: "calculator-key {props.name}"
|
class: "calculator-key {props.name}"
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ mod baller {
|
|||||||
pub struct BallerProps {}
|
pub struct BallerProps {}
|
||||||
|
|
||||||
/// This component totally balls
|
/// This component totally balls
|
||||||
pub fn Baller(_: Component<BallerProps>) -> Element {
|
pub fn Baller(_: Scope<BallerProps>) -> Element {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@ pub struct TallerProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This component is taller than most :)
|
/// This component is taller than most :)
|
||||||
pub fn Taller(_: Component<TallerProps>) -> Element {
|
pub fn Taller(_: Scope<TallerProps>) -> Element {
|
||||||
let b = true;
|
let b = true;
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
+1
-1
@@ -85,7 +85,7 @@ pub struct TodoEntryProps {
|
|||||||
todo: Rc<TodoItem>,
|
todo: Rc<TodoItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn TodoEntry((cx, props): Component<TodoEntryProps>) -> Element {
|
pub fn TodoEntry((cx, props): Scope<TodoEntryProps>) -> Element {
|
||||||
let is_editing = use_state(cx, || false);
|
let is_editing = use_state(cx, || false);
|
||||||
let contents = use_state(cx, || String::from(""));
|
let contents = use_state(cx, || String::from(""));
|
||||||
let todo = &props.todo;
|
let todo = &props.todo;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ struct RowProps {
|
|||||||
row_id: usize,
|
row_id: usize,
|
||||||
label: Label,
|
label: Label,
|
||||||
}
|
}
|
||||||
fn Row((cx, props): Component<RowProps>) -> Element {
|
fn Row((cx, props): Scope<RowProps>) -> Element {
|
||||||
let [adj, col, noun] = props.label.0;
|
let [adj, col, noun] = props.label.0;
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
tr {
|
tr {
|
||||||
|
|||||||
@@ -57,11 +57,11 @@ impl ToTokens for CallBody {
|
|||||||
}),
|
}),
|
||||||
// Otherwise we just build the LazyNode wrapper
|
// Otherwise we just build the LazyNode wrapper
|
||||||
None => out_tokens.append_all(quote! {
|
None => out_tokens.append_all(quote! {
|
||||||
Some(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
|
dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
|
||||||
use dioxus_elements::{GlobalAttributes, SvgAttributes};
|
use dioxus_elements::{GlobalAttributes, SvgAttributes};
|
||||||
|
|
||||||
#inner
|
#inner
|
||||||
}))
|
})
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"rust-analyzer.inlayHints.enable": true
|
|
||||||
}
|
|
||||||
@@ -42,8 +42,6 @@ serde = { version = "1", features = ["derive"], optional = true }
|
|||||||
|
|
||||||
serde_repr = { version = "0.1.7", optional = true }
|
serde_repr = { version = "0.1.7", optional = true }
|
||||||
|
|
||||||
stack_dst = "0.6.1"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0.42"
|
anyhow = "1.0.42"
|
||||||
dioxus-html = { path = "../html" }
|
dioxus-html = { path = "../html" }
|
||||||
|
|||||||
@@ -34,13 +34,13 @@ fn create_rows(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
rsx! {
|
cx.render(rsx! {
|
||||||
table {
|
table {
|
||||||
tbody {
|
tbody {
|
||||||
{rows}
|
{rows}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
c.bench_function("create rows", |b| {
|
c.bench_function("create rows", |b| {
|
||||||
@@ -57,9 +57,9 @@ struct RowProps {
|
|||||||
row_id: usize,
|
row_id: usize,
|
||||||
label: Label,
|
label: Label,
|
||||||
}
|
}
|
||||||
fn Row((cx, props): Component<RowProps>) -> Element {
|
fn Row((cx, props): Scope<RowProps>) -> Element {
|
||||||
let [adj, col, noun] = props.label.0;
|
let [adj, col, noun] = props.label.0;
|
||||||
rsx! {
|
cx.render(rsx! {
|
||||||
tr {
|
tr {
|
||||||
td { class:"col-md-1", "{props.row_id}" }
|
td { class:"col-md-1", "{props.row_id}" }
|
||||||
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
||||||
@@ -72,7 +72,7 @@ fn Row((cx, props): Component<RowProps>) -> Element {
|
|||||||
}
|
}
|
||||||
td { class: "col-md-6" }
|
td { class: "col-md-6" }
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ fn main() {
|
|||||||
pub static EXAMPLE: FC<()> = |(cx, _)| {
|
pub static EXAMPLE: FC<()> = |(cx, _)| {
|
||||||
let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!()));
|
let list = (0..10).map(|_f| LazyNodes::new(move |_f| todo!()));
|
||||||
|
|
||||||
Some(LazyNodes::new(move |cx| {
|
cx.render(LazyNodes::new(move |cx| {
|
||||||
cx.raw_element(
|
cx.raw_element(
|
||||||
"div",
|
"div",
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ struct ListItem {
|
|||||||
fn app<'a>(cx: Context<'a>, props: &AppProps) -> Element<'a> {
|
fn app<'a>(cx: Context<'a>, props: &AppProps) -> Element<'a> {
|
||||||
// let (val, set_val) = use_state_classic(cx, || 0);
|
// let (val, set_val) = use_state_classic(cx, || 0);
|
||||||
|
|
||||||
Some(LazyNodes::new(move |_nodecx| {
|
cx.render(LazyNodes::new(move |_nodecx| {
|
||||||
todo!()
|
todo!()
|
||||||
// builder::ElementBuilder::new(_nodecx, "div")
|
// builder::ElementBuilder::new(_nodecx, "div")
|
||||||
// .iter_child({
|
// .iter_child({
|
||||||
@@ -57,7 +57,7 @@ struct ChildProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ChildItem<'a>(cx: Context<'a>, props: &'a ChildProps) -> Element<'a> {
|
fn ChildItem<'a>(cx: Context<'a>, props: &'a ChildProps) -> Element<'a> {
|
||||||
Some(LazyNodes::new(move |__cx| todo!()))
|
cx.render(LazyNodes::new(move |__cx| todo!()))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for ChildProps {
|
impl PartialEq for ChildProps {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ fn app<'a>(cx: Context<'a>, props: &()) -> Element<'a> {
|
|||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Some(LazyNodes::new(move |f| {
|
cx.render(LazyNodes::new(move |f| {
|
||||||
f.raw_element(
|
f.raw_element(
|
||||||
"div",
|
"div",
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use dioxus::component::Component;
|
use dioxus::component::Scope;
|
||||||
use dioxus::events::on::MouseEvent;
|
use dioxus::events::on::MouseEvent;
|
||||||
use dioxus_core as dioxus;
|
use dioxus_core as dioxus;
|
||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
@@ -15,7 +15,7 @@ fn main() {
|
|||||||
assert!(g.edits.len() > 1);
|
assert!(g.edits.len() > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn App((cx, props): Component<()>) -> Element {
|
fn App((cx, props): Scope<()>) -> Element {
|
||||||
let mut rng = SmallRng::from_entropy();
|
let mut rng = SmallRng::from_entropy();
|
||||||
let rows = (0..10_000_usize).map(|f| {
|
let rows = (0..10_000_usize).map(|f| {
|
||||||
let label = Label::new(&mut rng);
|
let label = Label::new(&mut rng);
|
||||||
@@ -26,13 +26,13 @@ fn App((cx, props): Component<()>) -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
rsx! {
|
cx.render(rsx! {
|
||||||
table {
|
table {
|
||||||
tbody {
|
tbody {
|
||||||
{rows}
|
{rows}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Props)]
|
#[derive(PartialEq, Props)]
|
||||||
@@ -41,11 +41,11 @@ struct RowProps {
|
|||||||
label: Label,
|
label: Label,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Row((cx, props): Component<RowProps>) -> Element {
|
fn Row((cx, props): Scope<RowProps>) -> Element {
|
||||||
let handler = move |evt: MouseEvent| {
|
let handler = move |evt: MouseEvent| {
|
||||||
let g = evt.button;
|
let g = evt.button;
|
||||||
};
|
};
|
||||||
rsx! {
|
cx.render(rsx! {
|
||||||
tr {
|
tr {
|
||||||
td { class:"col-md-1", "{props.row_id}" }
|
td { class:"col-md-1", "{props.row_id}" }
|
||||||
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
|
||||||
@@ -58,7 +58,7 @@ fn Row((cx, props): Component<RowProps>) -> Element {
|
|||||||
}
|
}
|
||||||
td { class: "col-md-6" }
|
td { class: "col-md-6" }
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
use dioxus::component::Component;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use dioxus::component::Scope;
|
||||||
use dioxus::events::on::MouseEvent;
|
use dioxus::events::on::MouseEvent;
|
||||||
|
use dioxus::nodes::{IntoVNode, IntoVNodeList};
|
||||||
use dioxus_core as dioxus;
|
use dioxus_core as dioxus;
|
||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
use dioxus_core_macro::*;
|
use dioxus_core_macro::*;
|
||||||
@@ -20,20 +23,97 @@ fn html_usage() {
|
|||||||
|
|
||||||
let items = ["bob", "bill", "jack"];
|
let items = ["bob", "bill", "jack"];
|
||||||
|
|
||||||
let f = items.iter().filter(|f| f.starts_with("b")).map(|f| {
|
let f = items
|
||||||
rsx! {
|
.iter()
|
||||||
"hello {f}"
|
.filter(|f| f.starts_with('b'))
|
||||||
}
|
.map(|f| rsx!("hello {f}"));
|
||||||
});
|
|
||||||
|
|
||||||
let p = rsx! {
|
let p = rsx!(div { {f} });
|
||||||
div {
|
|
||||||
{f}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static App2: FC<()> = |(cx, _)| cx.render(rsx!("hello world!"));
|
||||||
|
|
||||||
static App: FC<()> = |(cx, props)| {
|
static App: FC<()> = |(cx, props)| {
|
||||||
//
|
let name = cx.use_state(|| 0);
|
||||||
rsx!(div {})
|
|
||||||
|
cx.render(rsx!(div {
|
||||||
|
h1 {}
|
||||||
|
h2 {}
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait UseState<'a, T: 'static> {
|
||||||
|
fn use_state(self, f: impl FnOnce() -> T) -> &'a T;
|
||||||
|
}
|
||||||
|
impl<'a, T: 'static> UseState<'a, T> for Context<'a> {
|
||||||
|
fn use_state(self, f: impl FnOnce() -> T) -> &'a T {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn App3((cx, props): Scope<()>) -> Element {
|
||||||
|
let p = rsx! {
|
||||||
|
Child {
|
||||||
|
bame: 10,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cx.render(rsx!(Child {
|
||||||
|
bame: 102,
|
||||||
|
..ChildProps { bame: 10 }
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props, PartialEq, Debug)]
|
||||||
|
struct ChildProps {
|
||||||
|
bame: i32, // children: Children<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Child<'a>((cx, props): Scope<'a, ChildProps>) -> Element<'a> {
|
||||||
|
cx.render(rsx!(div {
|
||||||
|
// {props.children}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some(LazyNodes::new(|f| {
|
||||||
|
// //
|
||||||
|
// // let r = f.fragment_from_iter(&props.children);
|
||||||
|
// r
|
||||||
|
// // todo!()
|
||||||
|
// }))
|
||||||
|
// todo!()
|
||||||
|
// rsx!({ Some(p) })
|
||||||
|
// todo!()
|
||||||
|
|
||||||
|
pub struct Children<'a> {
|
||||||
|
children: VNode<'static>,
|
||||||
|
_p: PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Children<'a> {
|
||||||
|
pub fn new(children: VNode<'a>) -> Self {
|
||||||
|
Self {
|
||||||
|
children: unsafe { std::mem::transmute(children) },
|
||||||
|
_p: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> IntoVNodeList<'a> for &Children<'a> {
|
||||||
|
fn into_vnode_list(self, cx: NodeFactory<'a>) -> &'a [VNode<'a>] {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bapp: FC<()> = |(cx, props)| {
|
||||||
|
let name = cx.use_state(|| 0);
|
||||||
|
|
||||||
|
cx.render(rsx!(
|
||||||
|
div {
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
};
|
};
|
||||||
@@ -4,7 +4,7 @@ use dioxus_core::prelude::*;
|
|||||||
|
|
||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
static App: FC<()> = |(cx, props)| Some(LazyNodes::new(|f| f.text(format_args!("hello"))));
|
static App: FC<()> = |(cx, props)| cx.render(LazyNodes::new(|f| f.text(format_args!("hello"))));
|
||||||
|
|
||||||
let mut dom = VirtualDom::new(App);
|
let mut dom = VirtualDom::new(App);
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ use crate::{
|
|||||||
/// };
|
/// };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
pub type Component<'a, T> = (Context<'a>, &'a T);
|
pub type Scope<'a, T> = (Context<'a>, &'a T);
|
||||||
|
|
||||||
/// Create inline fragments using Component syntax.
|
/// Create inline fragments using Component syntax.
|
||||||
///
|
///
|
||||||
@@ -66,8 +66,8 @@ pub type Component<'a, T> = (Context<'a>, &'a T);
|
|||||||
/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
|
/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it.
|
||||||
///
|
///
|
||||||
#[allow(non_upper_case_globals, non_snake_case)]
|
#[allow(non_upper_case_globals, non_snake_case)]
|
||||||
pub fn Fragment((cx, _): Component<()>) -> Element {
|
pub fn Fragment((cx, _): Scope<()>) -> Element {
|
||||||
Some(LazyNodes::new(|f| f.fragment_from_iter(cx.children())))
|
cx.render(LazyNodes::new(move |f| f.fragment_from_iter(cx.children())))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
|
/// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ use std::{any::TypeId, ops::Deref, rc::Rc};
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Context<'src> {
|
pub struct Context<'src> {
|
||||||
pub scope: &'src Scope,
|
pub scope: &'src ScopeInner,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Copy for Context<'src> {}
|
impl<'src> Copy for Context<'src> {}
|
||||||
@@ -45,7 +45,7 @@ impl<'src> Clone for Context<'src> {
|
|||||||
// We currently deref to props, but it might make more sense to deref to Scope?
|
// We currently deref to props, but it might make more sense to deref to Scope?
|
||||||
// This allows for code that takes cx.xyz instead of cx.props.xyz
|
// This allows for code that takes cx.xyz instead of cx.props.xyz
|
||||||
impl<'a> Deref for Context<'a> {
|
impl<'a> Deref for Context<'a> {
|
||||||
type Target = &'a Scope;
|
type Target = &'a ScopeInner;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.scope
|
&self.scope
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,10 @@ impl<'src> Context<'src> {
|
|||||||
/// cx.render(lazy_tree)
|
/// cx.render(lazy_tree)
|
||||||
/// }
|
/// }
|
||||||
///```
|
///```
|
||||||
pub fn render(self, lazy_nodes: LazyNodes<'src>) -> Option<VNode<'src>> {
|
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||||
|
self,
|
||||||
|
lazy_nodes: LazyNodes<'src, F>,
|
||||||
|
) -> Option<VNode<'src>> {
|
||||||
let bump = &self.scope.frames.wip_frame().bump;
|
let bump = &self.scope.frames.wip_frame().bump;
|
||||||
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ impl<'bump> DiffMachine<'bump> {
|
|||||||
let parent_scope = self.vdom.get_scope(parent_idx).unwrap();
|
let parent_scope = self.vdom.get_scope(parent_idx).unwrap();
|
||||||
|
|
||||||
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
|
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
|
||||||
Scope::new(
|
ScopeInner::new(
|
||||||
caller,
|
caller,
|
||||||
new_idx,
|
new_idx,
|
||||||
Some(parent_idx),
|
Some(parent_idx),
|
||||||
@@ -1161,7 +1161,7 @@ impl<'bump> DiffMachine<'bump> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a listener closure to a scope during diff.
|
/// Adds a listener closure to a scope during diff.
|
||||||
fn attach_listener_to_scope<'a>(&mut self, listener: &'a Listener<'a>, scope: &Scope) {
|
fn attach_listener_to_scope<'a>(&mut self, listener: &'a Listener<'a>, scope: &ScopeInner) {
|
||||||
let mut queue = scope.listeners.borrow_mut();
|
let mut queue = scope.listeners.borrow_mut();
|
||||||
let long_listener: &'a Listener<'static> = unsafe { std::mem::transmute(listener) };
|
let long_listener: &'a Listener<'static> = unsafe { std::mem::transmute(listener) };
|
||||||
queue.push(long_listener as *const _)
|
queue.push(long_listener as *const _)
|
||||||
|
|||||||
+27
-24
@@ -135,32 +135,35 @@ where
|
|||||||
None => {
|
None => {
|
||||||
let value = hook.value.clone();
|
let value = hook.value.clone();
|
||||||
|
|
||||||
Some(LazyNodes::new(|f| {
|
let id = hook.handle.our_id;
|
||||||
let bump = f.bump();
|
|
||||||
|
|
||||||
use bumpalo::boxed::Box as BumpBox;
|
todo!()
|
||||||
|
// Some(LazyNodes::new(move |f| {
|
||||||
|
// let bump = f.bump();
|
||||||
|
|
||||||
let f: &mut dyn FnMut(SuspendedContext<'src>) -> Element<'src> =
|
// use bumpalo::boxed::Box as BumpBox;
|
||||||
bump.alloc(move |sus| {
|
|
||||||
let val = value.borrow();
|
|
||||||
|
|
||||||
let out = val
|
// let f: &mut dyn FnMut(SuspendedContext<'src>) -> Element<'src> =
|
||||||
.as_ref()
|
// bump.alloc(move |sus| {
|
||||||
.unwrap()
|
// let val = value.borrow();
|
||||||
.as_ref()
|
|
||||||
.downcast_ref::<Out>()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
user_callback(sus, out)
|
// let out = val
|
||||||
});
|
// .as_ref()
|
||||||
let callback = unsafe { BumpBox::from_raw(f) };
|
// .unwrap()
|
||||||
|
// .as_ref()
|
||||||
|
// .downcast_ref::<Out>()
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
VNode::Suspended(bump.alloc(VSuspended {
|
// user_callback(sus, out)
|
||||||
dom_id: empty_cell(),
|
// });
|
||||||
task_id: hook.handle.our_id,
|
// let callback = unsafe { BumpBox::from_raw(f) };
|
||||||
callback: RefCell::new(Some(callback)),
|
|
||||||
}))
|
// VNode::Suspended(bump.alloc(VSuspended {
|
||||||
}))
|
// dom_id: empty_cell(),
|
||||||
|
// task_id: id,
|
||||||
|
// callback: RefCell::new(Some(callback)),
|
||||||
|
// }))
|
||||||
|
// }))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|_| {},
|
|_| {},
|
||||||
@@ -177,10 +180,10 @@ pub struct SuspendedContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> SuspendedContext<'src> {
|
impl<'src> SuspendedContext<'src> {
|
||||||
pub fn render(
|
// pub fn render(
|
||||||
// pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
pub fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||||
self,
|
self,
|
||||||
lazy_nodes: LazyNodes<'src>,
|
lazy_nodes: LazyNodes<'src, F>,
|
||||||
) -> Element<'src> {
|
) -> Element<'src> {
|
||||||
let bump = &self.inner.scope.frames.wip_frame().bump;
|
let bump = &self.inner.scope.frames.wip_frame().bump;
|
||||||
todo!("suspense")
|
todo!("suspense")
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Remember: calls to rsx! are lazy - they are not evaluated immediately.
|
||||||
|
|
||||||
|
They also using dynamic dispatch, so we can return multiple rsx!'s from match statements and such.
|
||||||
|
|
||||||
|
If we allocated every rsx! call on the heap, it would be quite wasteful. Rsx! calls are FnOnce, so they can be stored in a stack.
|
||||||
|
|
||||||
|
Solutions like stackdst are useful, but they only support 'static closures.
|
||||||
|
|
||||||
|
All our closures are bound by the bump lifetime, so stack-dst will not work for us
|
||||||
|
|
||||||
|
Our solution is to try and manually allocate the closure onto the stack.
|
||||||
|
If it fails, then we default to Box.
|
||||||
|
|
||||||
|
*/
|
||||||
|
use crate::innerlude::{IntoVNode, NodeFactory, VNode};
|
||||||
|
|
||||||
|
/// A concrete type provider for closures that build VNode structures.
|
||||||
|
///
|
||||||
|
/// This struct wraps lazy structs that build VNode trees Normally, we cannot perform a blanket implementation over
|
||||||
|
/// closures, but if we wrap the closure in a concrete type, we can maintain separate implementations of IntoVNode.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// LazyNodes::new(|f| f.element("div", [], [], [] None))
|
||||||
|
/// ```
|
||||||
|
pub struct LazyNodes<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> {
|
||||||
|
inner: Box<F>,
|
||||||
|
_p: PhantomData<&'a ()>,
|
||||||
|
// inner: StackNodeStorage<'a>,
|
||||||
|
// inner: StackNodeStorage<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type StackHeapSize = [usize; 12];
|
||||||
|
|
||||||
|
enum StackNodeStorage<'a> {
|
||||||
|
Stack {
|
||||||
|
next_ofs: usize,
|
||||||
|
buf: StackHeapSize,
|
||||||
|
width: usize,
|
||||||
|
},
|
||||||
|
Heap(Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> LazyNodes<'a, F> {
|
||||||
|
pub fn new(f: F) -> Self {
|
||||||
|
// let width = std::mem?::size_of::<F>();
|
||||||
|
// let b: Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>> = Box::new(f);
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
// Self { inner: b }
|
||||||
|
// todo!()
|
||||||
|
|
||||||
|
// if width > std::mem::size_of::<StackHeapSize>() {
|
||||||
|
// let g: Box<dyn for<'b> FnOnce(NodeFactory<'b>) -> VNode<'b> + 'g> = Box::new(f);
|
||||||
|
// LazyNodes {
|
||||||
|
// inner: StackNodeStorage::Heap(g),
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// let mut buf = [0; 12];
|
||||||
|
// let mut next_ofs = 0;
|
||||||
|
// next_ofs += 1;
|
||||||
|
// LazyNodes {
|
||||||
|
// inner: StackNodeStorage::Stack {
|
||||||
|
// next_ofs,
|
||||||
|
// buf,
|
||||||
|
// width,
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our blanket impl
|
||||||
|
impl<'a, F> IntoIterator for LazyNodes<'a, F>
|
||||||
|
where
|
||||||
|
F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||||
|
{
|
||||||
|
type Item = Self;
|
||||||
|
type IntoIter = std::iter::Once<Self::Item>;
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
std::iter::once(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our blanket impl
|
||||||
|
impl<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> IntoVNode<'a> for LazyNodes<'a, F> {
|
||||||
|
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||||
|
todo!()
|
||||||
|
// match self.inner {
|
||||||
|
// StackNodeStorage::Stack {
|
||||||
|
// buf,
|
||||||
|
// next_ofs,
|
||||||
|
// width,
|
||||||
|
// } => {
|
||||||
|
// // get the start of the allocation
|
||||||
|
// let r = &buf[0];
|
||||||
|
|
||||||
|
// // recast the allocation as dyn FnOnce
|
||||||
|
|
||||||
|
// // pretend the FnOnce is box
|
||||||
|
// let g: Box<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>> = todo!();
|
||||||
|
// // Box::from_raw(r as *const usize as *mut dyn FnOnce(NodeFactory<'a>));
|
||||||
|
|
||||||
|
// // use Box's ability to act as FnOnce
|
||||||
|
// g(cx)
|
||||||
|
// }
|
||||||
|
// StackNodeStorage::Heap(b) => b(cx),
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ pub mod events;
|
|||||||
pub mod heuristics;
|
pub mod heuristics;
|
||||||
pub mod hooklist;
|
pub mod hooklist;
|
||||||
pub mod hooks;
|
pub mod hooks;
|
||||||
|
pub mod lazynodes;
|
||||||
pub mod mutations;
|
pub mod mutations;
|
||||||
pub mod nodes;
|
pub mod nodes;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
@@ -45,6 +46,7 @@ pub(crate) mod innerlude {
|
|||||||
pub use crate::heuristics::*;
|
pub use crate::heuristics::*;
|
||||||
pub(crate) use crate::hooklist::*;
|
pub(crate) use crate::hooklist::*;
|
||||||
pub use crate::hooks::*;
|
pub use crate::hooks::*;
|
||||||
|
pub use crate::lazynodes::LazyNodes;
|
||||||
pub use crate::mutations::*;
|
pub use crate::mutations::*;
|
||||||
pub use crate::nodes::*;
|
pub use crate::nodes::*;
|
||||||
pub(crate) use crate::resources::*;
|
pub(crate) use crate::resources::*;
|
||||||
@@ -55,10 +57,9 @@ pub(crate) mod innerlude {
|
|||||||
pub use crate::threadsafe::*;
|
pub use crate::threadsafe::*;
|
||||||
pub use crate::util::*;
|
pub use crate::util::*;
|
||||||
pub use crate::virtual_dom::*;
|
pub use crate::virtual_dom::*;
|
||||||
|
|
||||||
// pub type Element<'a> = Option<VNode<'a>>;
|
// pub type Element<'a> = Option<VNode<'a>>;
|
||||||
pub type Element<'a> = Option<LazyNodes<'a>>;
|
pub type Element<'a> = Option<VNode<'a>>;
|
||||||
pub type FC<P> = for<'a> fn(Component<'a, P>) -> Element<'a>;
|
pub type FC<P> = for<'a> fn(Scope<'a, P>) -> Element<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::innerlude::{
|
pub use crate::innerlude::{
|
||||||
@@ -68,7 +69,7 @@ pub use crate::innerlude::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::component::{fc_to_builder, Component, Fragment, Properties};
|
pub use crate::component::{fc_to_builder, Fragment, Properties, Scope};
|
||||||
pub use crate::context::Context;
|
pub use crate::context::Context;
|
||||||
pub use crate::hooks::*;
|
pub use crate::hooks::*;
|
||||||
pub use crate::innerlude::{DioxusElement, Element, LazyNodes, Mutations, NodeFactory, FC};
|
pub use crate::innerlude::{DioxusElement, Element, LazyNodes, Mutations, NodeFactory, FC};
|
||||||
|
|||||||
+10
-67
@@ -4,7 +4,8 @@
|
|||||||
//! cheap and *very* fast to construct - building a full tree should be quick.
|
//! cheap and *very* fast to construct - building a full tree should be quick.
|
||||||
|
|
||||||
use crate::innerlude::{
|
use crate::innerlude::{
|
||||||
empty_cell, Context, Element, ElementId, Properties, Scope, ScopeId, SuspendedContext, FC,
|
empty_cell, Context, Element, ElementId, LazyNodes, Properties, ScopeId, ScopeInner,
|
||||||
|
SuspendedContext, FC,
|
||||||
};
|
};
|
||||||
use bumpalo::{boxed::Box as BumpBox, Bump};
|
use bumpalo::{boxed::Box as BumpBox, Bump};
|
||||||
use std::{
|
use std::{
|
||||||
@@ -13,10 +14,6 @@ use std::{
|
|||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
use stack_dst::Value as StackDST;
|
|
||||||
|
|
||||||
pub type LazyNodeFactory<'a> = StackDST<dyn FnOnce(NodeFactory<'a>) -> VNode<'a>>;
|
|
||||||
|
|
||||||
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
||||||
///
|
///
|
||||||
/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
|
/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
|
||||||
@@ -291,7 +288,7 @@ pub struct VComponent<'src> {
|
|||||||
// Function pointer to the FC that was used to generate this component
|
// Function pointer to the FC that was used to generate this component
|
||||||
pub user_fc: *const (),
|
pub user_fc: *const (),
|
||||||
|
|
||||||
pub(crate) caller: &'src dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
pub(crate) caller: &'src dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
|
||||||
|
|
||||||
pub(crate) children: &'src [VNode<'src>],
|
pub(crate) children: &'src [VNode<'src>],
|
||||||
|
|
||||||
@@ -332,11 +329,11 @@ impl<'a> NodeFactory<'a> {
|
|||||||
self.bump
|
self.bump
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a>) -> Option<VNode<'a>>
|
pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a, F>) -> Element<'a>
|
||||||
// pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a, F>) -> Element<'a>
|
where
|
||||||
// where
|
F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||||
// F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
|
||||||
{
|
{
|
||||||
|
// pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a>) -> Option<VNode<'a>> {
|
||||||
Some(lazy_nodes.into_vnode(NodeFactory { bump: self.bump }))
|
Some(lazy_nodes.into_vnode(NodeFactory { bump: self.bump }))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,8 +528,8 @@ impl<'a> NodeFactory<'a> {
|
|||||||
|
|
||||||
let key = key.map(|f| self.raw_text(f).0);
|
let key = key.map(|f| self.raw_text(f).0);
|
||||||
|
|
||||||
let caller: &'a mut dyn for<'b> Fn(&'b Scope) -> Element<'b> =
|
let caller: &'a mut dyn for<'b> Fn(&'b ScopeInner) -> Element<'b> =
|
||||||
bump.alloc(move |scope: &Scope| -> Element {
|
bump.alloc(move |scope: &ScopeInner| -> Element {
|
||||||
log::debug!("calling component renderr {:?}", scope.our_arena_idx);
|
log::debug!("calling component renderr {:?}", scope.our_arena_idx);
|
||||||
let props: &'_ P = unsafe { &*(raw_props as *const P) };
|
let props: &'_ P = unsafe { &*(raw_props as *const P) };
|
||||||
let res: Element = component((Context { scope }, props));
|
let res: Element = component((Context { scope }, props));
|
||||||
@@ -687,60 +684,6 @@ impl<'a> IntoVNode<'a> for VNode<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A concrete type provider for closures that build VNode structures.
|
|
||||||
///
|
|
||||||
/// This struct wraps lazy structs that build VNode trees Normally, we cannot perform a blanket implementation over
|
|
||||||
/// closures, but if we wrap the closure in a concrete type, we can maintain separate implementations of IntoVNode.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// LazyNodes::new(|f| f.element("div", [], [], [] None))
|
|
||||||
/// ```
|
|
||||||
pub struct LazyNodes<'a> {
|
|
||||||
inner: LazyNodeFactory<'a>,
|
|
||||||
}
|
|
||||||
// where
|
|
||||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
|
||||||
|
|
||||||
impl<'a> LazyNodes<'a>
|
|
||||||
// where
|
|
||||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
|
||||||
{
|
|
||||||
pub fn new(f: impl FnOnce(NodeFactory<'a>) -> VNode<'a>) -> Self {
|
|
||||||
todo!()
|
|
||||||
// pub fn new<G: FnOnce(NodeFactory<'a>) -> VNode<'a>>(f: G) -> Self {
|
|
||||||
// let inner = LazyNodeFactory::new(f);
|
|
||||||
// Self { inner: f }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our blanket impl
|
|
||||||
impl<'a> IntoVNode<'a> for LazyNodes<'a>
|
|
||||||
// where
|
|
||||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
|
||||||
{
|
|
||||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
|
||||||
// let f = self.inner;
|
|
||||||
todo!("manually drop here")
|
|
||||||
// (self.inner)(cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our blanket impl
|
|
||||||
impl<'a> IntoIterator for LazyNodes<'a>
|
|
||||||
// where
|
|
||||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
|
||||||
// impl<'a, G> IntoIterator for LazyNodes<'a, G>
|
|
||||||
// where
|
|
||||||
// G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
|
||||||
{
|
|
||||||
type Item = Self;
|
|
||||||
type IntoIter = std::iter::Once<Self::Item>;
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
std::iter::once(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conveniently, we also support "null" (nothing) passed in
|
// Conveniently, we also support "null" (nothing) passed in
|
||||||
impl IntoVNode<'_> for () {
|
impl IntoVNode<'_> for () {
|
||||||
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
fn into_vnode(self, cx: NodeFactory) -> VNode {
|
||||||
@@ -764,7 +707,7 @@ impl<'a> IntoVNode<'a> for Option<VNode<'a>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoVNode<'a> for Option<LazyNodes<'a>> {
|
impl<'a, F: FnOnce(NodeFactory<'a>) -> VNode<'a>> IntoVNode<'a> for Option<LazyNodes<'a, F>> {
|
||||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||||
match self {
|
match self {
|
||||||
Some(n) => n.into_vnode(cx),
|
Some(n) => n.into_vnode(cx),
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub(crate) struct ResourcePool {
|
|||||||
|
|
||||||
Wrapped in Rc so the "get_shared_context" closure can walk the tree (immutably!)
|
Wrapped in Rc so the "get_shared_context" closure can walk the tree (immutably!)
|
||||||
*/
|
*/
|
||||||
pub components: Rc<UnsafeCell<Slab<Scope>>>,
|
pub components: Rc<UnsafeCell<Slab<ScopeInner>>>,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Yes, a slab of "nil". We use this for properly ordering ElementIDs - all we care about is the allocation strategy
|
Yes, a slab of "nil". We use this for properly ordering ElementIDs - all we care about is the allocation strategy
|
||||||
@@ -32,18 +32,18 @@ pub(crate) struct ResourcePool {
|
|||||||
|
|
||||||
impl ResourcePool {
|
impl ResourcePool {
|
||||||
/// this is unsafe because the caller needs to track which other scopes it's already using
|
/// this is unsafe because the caller needs to track which other scopes it's already using
|
||||||
pub fn get_scope(&self, idx: ScopeId) -> Option<&Scope> {
|
pub fn get_scope(&self, idx: ScopeId) -> Option<&ScopeInner> {
|
||||||
let inner = unsafe { &*self.components.get() };
|
let inner = unsafe { &*self.components.get() };
|
||||||
inner.get(idx.0)
|
inner.get(idx.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// this is unsafe because the caller needs to track which other scopes it's already using
|
/// this is unsafe because the caller needs to track which other scopes it's already using
|
||||||
pub fn get_scope_mut(&self, idx: ScopeId) -> Option<&mut Scope> {
|
pub fn get_scope_mut(&self, idx: ScopeId) -> Option<&mut ScopeInner> {
|
||||||
let inner = unsafe { &mut *self.components.get() };
|
let inner = unsafe { &mut *self.components.get() };
|
||||||
inner.get_mut(idx.0)
|
inner.get_mut(idx.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_remove(&self, id: ScopeId) -> Option<Scope> {
|
pub fn try_remove(&self, id: ScopeId) -> Option<ScopeInner> {
|
||||||
let inner = unsafe { &mut *self.components.get() };
|
let inner = unsafe { &mut *self.components.get() };
|
||||||
Some(inner.remove(id.0))
|
Some(inner.remove(id.0))
|
||||||
// .try_remove(id.0)
|
// .try_remove(id.0)
|
||||||
@@ -67,7 +67,7 @@ impl ResourcePool {
|
|||||||
els.remove(id.0);
|
els.remove(id.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_scope_with_key(&self, f: impl FnOnce(ScopeId) -> Scope) -> ScopeId {
|
pub fn insert_scope_with_key(&self, f: impl FnOnce(ScopeId) -> ScopeInner) -> ScopeId {
|
||||||
let g = unsafe { &mut *self.components.get() };
|
let g = unsafe { &mut *self.components.get() };
|
||||||
let entry = g.vacant_entry();
|
let entry = g.vacant_entry();
|
||||||
let id = ScopeId(entry.key());
|
let id = ScopeId(entry.key());
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ impl Scheduler {
|
|||||||
let components = components.clone();
|
let components = components.clone();
|
||||||
Rc::new(move |id, ty| {
|
Rc::new(move |id, ty| {
|
||||||
let components = unsafe { &*components.get() };
|
let components = unsafe { &*components.get() };
|
||||||
let mut search: Option<&Scope> = components.get(id.0);
|
let mut search: Option<&ScopeInner> = components.get(id.0);
|
||||||
while let Some(inner) = search.take() {
|
while let Some(inner) = search.take() {
|
||||||
if let Some(shared) = inner.shared_contexts.borrow().get(&ty) {
|
if let Some(shared) = inner.shared_contexts.borrow().get(&ty) {
|
||||||
return Some(shared.clone());
|
return Some(shared.clone());
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use std::{
|
|||||||
///
|
///
|
||||||
/// We expose the `Scope` type so downstream users can traverse the Dioxus VirtualDOM for whatever
|
/// We expose the `Scope` type so downstream users can traverse the Dioxus VirtualDOM for whatever
|
||||||
/// use case they might have.
|
/// use case they might have.
|
||||||
pub struct Scope {
|
pub struct ScopeInner {
|
||||||
// Book-keeping about our spot in the arena
|
// Book-keeping about our spot in the arena
|
||||||
pub(crate) parent_idx: Option<ScopeId>,
|
pub(crate) parent_idx: Option<ScopeId>,
|
||||||
pub(crate) our_arena_idx: ScopeId,
|
pub(crate) our_arena_idx: ScopeId,
|
||||||
@@ -28,7 +28,7 @@ pub struct Scope {
|
|||||||
|
|
||||||
// Nodes
|
// Nodes
|
||||||
pub(crate) frames: ActiveFrame,
|
pub(crate) frames: ActiveFrame,
|
||||||
pub(crate) caller: *const dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
pub(crate) caller: *const dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
|
||||||
pub(crate) child_nodes: ScopeChildren<'static>,
|
pub(crate) child_nodes: ScopeChildren<'static>,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -55,7 +55,7 @@ pub struct Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Public interface for Scopes.
|
/// Public interface for Scopes.
|
||||||
impl Scope {
|
impl ScopeInner {
|
||||||
/// Get the root VNode for this Scope.
|
/// Get the root VNode for this Scope.
|
||||||
///
|
///
|
||||||
/// This VNode is the "entrypoint" VNode. If the component renders multiple nodes, then this VNode will be a fragment.
|
/// This VNode is the "entrypoint" VNode. If the component renders multiple nodes, then this VNode will be a fragment.
|
||||||
@@ -167,7 +167,7 @@ impl Scope {
|
|||||||
pub type FiberTask = Pin<Box<dyn Future<Output = ScopeId>>>;
|
pub type FiberTask = Pin<Box<dyn Future<Output = ScopeId>>>;
|
||||||
|
|
||||||
/// Private interface for Scopes.
|
/// Private interface for Scopes.
|
||||||
impl Scope {
|
impl ScopeInner {
|
||||||
// we are being created in the scope of an existing component (where the creator_node lifetime comes into play)
|
// we are being created in the scope of an existing component (where the creator_node lifetime comes into play)
|
||||||
// we are going to break this lifetime by force in order to save it on ourselves.
|
// we are going to break this lifetime by force in order to save it on ourselves.
|
||||||
// To make sure that the lifetime isn't truly broken, we receive a Weak RC so we can't keep it around after the parent dies.
|
// To make sure that the lifetime isn't truly broken, we receive a Weak RC so we can't keep it around after the parent dies.
|
||||||
@@ -176,7 +176,7 @@ impl Scope {
|
|||||||
// Scopes cannot be made anywhere else except for this file
|
// Scopes cannot be made anywhere else except for this file
|
||||||
// Therefore, their lifetimes are connected exclusively to the virtual dom
|
// Therefore, their lifetimes are connected exclusively to the virtual dom
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
caller: &dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
caller: &dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
|
||||||
our_arena_idx: ScopeId,
|
our_arena_idx: ScopeId,
|
||||||
parent_idx: Option<ScopeId>,
|
parent_idx: Option<ScopeId>,
|
||||||
height: u32,
|
height: u32,
|
||||||
@@ -217,7 +217,7 @@ impl Scope {
|
|||||||
|
|
||||||
pub(crate) fn update_scope_dependencies<'creator_node>(
|
pub(crate) fn update_scope_dependencies<'creator_node>(
|
||||||
&mut self,
|
&mut self,
|
||||||
caller: &'creator_node dyn for<'b> Fn(&'b Scope) -> Element<'b>,
|
caller: &'creator_node dyn for<'b> Fn(&'b ScopeInner) -> Element<'b>,
|
||||||
child_nodes: ScopeChildren,
|
child_nodes: ScopeChildren,
|
||||||
) {
|
) {
|
||||||
log::debug!("Updating scope dependencies {:?}", self.our_arena_idx);
|
log::debug!("Updating scope dependencies {:?}", self.our_arena_idx);
|
||||||
@@ -350,7 +350,7 @@ impl Scope {
|
|||||||
log::debug!("Borrowed stuff is successfully cleared");
|
log::debug!("Borrowed stuff is successfully cleared");
|
||||||
|
|
||||||
// Cast the caller ptr from static to one with our own reference
|
// Cast the caller ptr from static to one with our own reference
|
||||||
let render: &dyn for<'b> Fn(&'b Scope) -> Element<'b> = unsafe { &*self.caller };
|
let render: &dyn for<'b> Fn(&'b ScopeInner) -> Element<'b> = unsafe { &*self.caller };
|
||||||
|
|
||||||
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
|
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
|
||||||
//
|
//
|
||||||
@@ -376,7 +376,7 @@ impl Scope {
|
|||||||
pub(crate) struct ScopeRenderer<'a> {
|
pub(crate) struct ScopeRenderer<'a> {
|
||||||
pub skip_components: bool,
|
pub skip_components: bool,
|
||||||
pub show_fragments: bool,
|
pub show_fragments: bool,
|
||||||
pub _scope: &'a Scope,
|
pub _scope: &'a ScopeInner,
|
||||||
pub _pre_render: bool,
|
pub _pre_render: bool,
|
||||||
pub _newline: bool,
|
pub _newline: bool,
|
||||||
pub _indent: bool,
|
pub _indent: bool,
|
||||||
|
|||||||
@@ -143,15 +143,16 @@ impl VirtualDom {
|
|||||||
|
|
||||||
let _p = root_props.clone();
|
let _p = root_props.clone();
|
||||||
// Safety: this callback is only valid for the lifetime of the root props
|
// Safety: this callback is only valid for the lifetime of the root props
|
||||||
let root_caller: Rc<dyn Fn(&Scope) -> Element> = Rc::new(move |scope: &Scope| unsafe {
|
let root_caller: Rc<dyn Fn(&ScopeInner) -> Element> =
|
||||||
let props = _p.downcast_ref::<P>().unwrap();
|
Rc::new(move |scope: &ScopeInner| unsafe {
|
||||||
std::mem::transmute(root((Context { scope }, props)))
|
let props = _p.downcast_ref::<P>().unwrap();
|
||||||
});
|
std::mem::transmute(root((Context { scope }, props)))
|
||||||
|
});
|
||||||
|
|
||||||
let scheduler = Scheduler::new(sender, receiver);
|
let scheduler = Scheduler::new(sender, receiver);
|
||||||
|
|
||||||
let base_scope = scheduler.pool.insert_scope_with_key(|myidx| {
|
let base_scope = scheduler.pool.insert_scope_with_key(|myidx| {
|
||||||
Scope::new(
|
ScopeInner::new(
|
||||||
root_caller.as_ref(),
|
root_caller.as_ref(),
|
||||||
myidx,
|
myidx,
|
||||||
None,
|
None,
|
||||||
@@ -175,12 +176,12 @@ impl VirtualDom {
|
|||||||
///
|
///
|
||||||
/// This is useful for traversing the tree from the root for heuristics or alternsative renderers that use Dioxus
|
/// This is useful for traversing the tree from the root for heuristics or alternsative renderers that use Dioxus
|
||||||
/// directly.
|
/// directly.
|
||||||
pub fn base_scope(&self) -> &Scope {
|
pub fn base_scope(&self) -> &ScopeInner {
|
||||||
self.scheduler.pool.get_scope(self.base_scope).unwrap()
|
self.scheduler.pool.get_scope(self.base_scope).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the [`Scope`] for a component given its [`ScopeId`]
|
/// Get the [`Scope`] for a component given its [`ScopeId`]
|
||||||
pub fn get_scope(&self, id: ScopeId) -> Option<&Scope> {
|
pub fn get_scope(&self, id: ScopeId) -> Option<&ScopeInner> {
|
||||||
self.scheduler.pool.get_scope(id)
|
self.scheduler.pool.get_scope(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,8 +220,8 @@ impl VirtualDom {
|
|||||||
|
|
||||||
let root = *self.root_fc.downcast_ref::<FC<P>>().unwrap();
|
let root = *self.root_fc.downcast_ref::<FC<P>>().unwrap();
|
||||||
|
|
||||||
let root_caller: Box<dyn Fn(&Scope) -> Element> =
|
let root_caller: Box<dyn Fn(&ScopeInner) -> Element> =
|
||||||
Box::new(move |scope: &Scope| unsafe {
|
Box::new(move |scope: &ScopeInner| unsafe {
|
||||||
let props: &'_ P = &*(props_ptr as *const P);
|
let props: &'_ P = &*(props_ptr as *const P);
|
||||||
std::mem::transmute(root((Context { scope }, props)))
|
std::mem::transmute(root((Context { scope }, props)))
|
||||||
});
|
});
|
||||||
@@ -410,4 +411,4 @@ impl std::fmt::Display for VirtualDom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we never actually use the contents of this root caller
|
// we never actually use the contents of this root caller
|
||||||
struct RootCaller(Rc<dyn for<'b> Fn(&'b Scope) -> Element<'b> + 'static>);
|
struct RootCaller(Rc<dyn for<'b> Fn(&'b ScopeInner) -> Element<'b> + 'static>);
|
||||||
@@ -10,7 +10,7 @@ fn test_borrowed_state() {
|
|||||||
let _ = VirtualDom::new(Parent);
|
let _ = VirtualDom::new(Parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Parent((cx, _): Component<()>) -> Element {
|
fn Parent((cx, _): Scope<()>) -> Element {
|
||||||
let value = cx.use_hook(|_| String::new(), |f| &*f, |_| {});
|
let value = cx.use_hook(|_| String::new(), |f| &*f, |_| {});
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
@@ -28,7 +28,7 @@ struct ChildProps<'a> {
|
|||||||
name: &'a str,
|
name: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Child<'a>((cx, props): Component<'a, ChildProps>) -> Element<'a> {
|
fn Child<'a>((cx, props): Scope<'a, ChildProps>) -> Element<'a> {
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
h1 { "it's nested" }
|
h1 { "it's nested" }
|
||||||
@@ -42,7 +42,7 @@ struct Grandchild<'a> {
|
|||||||
name: &'a str,
|
name: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Child2<'a>((cx, props): Component<'a, Grandchild>) -> Element<'a> {
|
fn Child2<'a>((cx, props): Scope<'a, Grandchild>) -> Element<'a> {
|
||||||
rsx! {
|
rsx! {
|
||||||
div { "Hello {props.name}!" }
|
div { "Hello {props.name}!" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ fn child_components() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn suspended_works() {
|
fn suspended_works() {
|
||||||
static App: FC<()> = |(cx, props)| {
|
static App: FC<()> = |(cx, props)| {
|
||||||
let title = use_suspense(cx, || async { "bob" }, |cx, f| rsx! { "{f}"});
|
let title = use_suspense(cx, || async { "bob" }, move |cx, f| rsx! { "{f}"});
|
||||||
rsx!("hello" { title })
|
rsx!("hello" { title })
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ pub struct TodoEntryProps {
|
|||||||
id: u32,
|
id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn TodoEntry((cx, props): Component<TodoEntryProps>) -> Element {
|
pub fn TodoEntry((cx, props): Scope<TodoEntryProps>) -> Element {
|
||||||
let todos = use_shared_state::<Todos>(cx)?;
|
let todos = use_shared_state::<Todos>(cx)?;
|
||||||
|
|
||||||
let _todos = todos.read();
|
let _todos = todos.read();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use dioxus::prelude::Component;
|
use dioxus::prelude::Scope;
|
||||||
use dioxus_core as dioxus;
|
use dioxus_core as dioxus;
|
||||||
use dioxus_core::{Context, Element, LazyNodes, NodeFactory, Properties};
|
use dioxus_core::{Context, Element, LazyNodes, NodeFactory, Properties};
|
||||||
use dioxus_core_macro::Props;
|
use dioxus_core_macro::Props;
|
||||||
@@ -54,7 +54,7 @@ pub struct WebviewWindowProps<'a> {
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
pub fn WebviewWindow<'a>((cx, props): Component<'a, WebviewWindowProps>) -> Element<'a> {
|
pub fn WebviewWindow<'a>((cx, props): Scope<'a, WebviewWindowProps>) -> Element<'a> {
|
||||||
let dtcx = cx.consume_state::<RefCell<DesktopContext>>()?;
|
let dtcx = cx.consume_state::<RefCell<DesktopContext>>()?;
|
||||||
|
|
||||||
cx.use_hook(
|
cx.use_hook(
|
||||||
|
|||||||
Reference in new issue
Block a user