mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 14:44:12 +00:00
Feat: props now autoderives its own trait
This commit is contained in:
parent
d4f1ceaffb
commit
b3c96a5996
10 changed files with 123 additions and 83 deletions
19
packages/core-macro/examples/prop_test.rs
Normal file
19
packages/core-macro/examples/prop_test.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
pub mod dioxus {
|
||||||
|
pub mod prelude {
|
||||||
|
pub trait Properties {
|
||||||
|
type Builder;
|
||||||
|
fn builder() -> Self::Builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(dioxus_core_macro::Props)]
|
||||||
|
struct SomeProps {
|
||||||
|
a: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(dioxus_core_macro::Props)]
|
||||||
|
struct SomePropsTwo<'a> {
|
||||||
|
a: &'a str,
|
||||||
|
}
|
|
@ -678,6 +678,14 @@ Finally, call `.build()` to create the instance of `{name}`.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl #impl_generics dioxus::prelude::Properties for #name #ty_generics{
|
||||||
|
type Builder = #builder_name #generics_with_empty;
|
||||||
|
fn builder() -> Self::Builder {
|
||||||
|
#name::builder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1071,6 +1079,13 @@ Finally, call `.build()` to create the instance of `{name}`.
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_props_impl(&self) -> TokenStream {
|
||||||
|
// SomeProps: #name
|
||||||
|
// #builder_name
|
||||||
|
// #generics_with_empty
|
||||||
|
quote! {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
|
|
@ -69,13 +69,6 @@ impl PartialEq for ChildProps<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Properties for ChildProps<'a> {
|
|
||||||
type Builder = ChildPropsBuilder<'a, ((), ())>;
|
|
||||||
fn builder() -> <Self as Properties>::Builder {
|
|
||||||
ChildProps::builder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ChildItem(_ctx: Context, _props: &ChildProps) -> DomTree {
|
fn ChildItem(_ctx: Context, _props: &ChildProps) -> DomTree {
|
||||||
todo!()
|
todo!()
|
||||||
// ctx.render(rsx! {
|
// ctx.render(rsx! {
|
||||||
|
|
|
@ -24,10 +24,3 @@ static SomeComponent: FC<ExampleProps> = |ctx, _props| {
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
||||||
impl Properties for ExampleProps {
|
|
||||||
type Builder = ExamplePropsBuilder<((),)>;
|
|
||||||
fn builder() -> Self::Builder {
|
|
||||||
ExampleProps::builder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use dioxus_core_macro::Props;
|
use dioxus_core::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Props)]
|
#[derive(Debug, PartialEq, Props)]
|
||||||
struct SomeProps {
|
struct SomeProps {
|
||||||
a: i32,
|
a: i32,
|
||||||
|
|
||||||
|
@ -9,12 +9,8 @@ struct SomeProps {
|
||||||
b: Option<i32>,
|
b: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// have we committed to the trait style yet?
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let g: SomeProps = SomeProps::builder().a(10).b(10).build();
|
let g: SomeProps = SomeProps::builder().a(10).b(10).build();
|
||||||
|
|
||||||
let _r = g.b.unwrap_or_else(|| 10);
|
let _r = g.b.unwrap_or_else(|| 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn auto_into_some() {}
|
|
||||||
|
|
|
@ -23,11 +23,3 @@ static Example: FC<SomeProps> = |ctx, _props| {
|
||||||
</div>
|
</div>
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// toodo: derive this
|
|
||||||
impl Properties for SomeProps {
|
|
||||||
type Builder = SomePropsBuilder<((),)>;
|
|
||||||
fn builder() -> Self::Builder {
|
|
||||||
SomeProps::builder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ use std::{
|
||||||
cell::{RefCell, RefMut},
|
cell::{RefCell, RefMut},
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
rc::Rc,
|
rc::{Rc, Weak},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The DiffState is a cursor internal to the VirtualDOM's diffing algorithm that allows persistence of state while
|
/// The DiffState is a cursor internal to the VirtualDOM's diffing algorithm that allows persistence of state while
|
||||||
|
@ -62,11 +62,9 @@ pub struct DiffMachine<'a> {
|
||||||
pub diffed: FxHashSet<ScopeIdx>,
|
pub diffed: FxHashSet<ScopeIdx>,
|
||||||
pub lifecycle_events: VecDeque<LifeCycleEvent<'a>>,
|
pub lifecycle_events: VecDeque<LifeCycleEvent<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Debug)]
|
|
||||||
pub enum LifeCycleEvent<'a> {
|
pub enum LifeCycleEvent<'a> {
|
||||||
Mount {
|
Mount {
|
||||||
caller: Rc<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
|
caller: Weak<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
|
||||||
id: Uuid,
|
id: Uuid,
|
||||||
},
|
},
|
||||||
PropsChanged,
|
PropsChanged,
|
||||||
|
@ -76,7 +74,6 @@ pub enum LifeCycleEvent<'a> {
|
||||||
|
|
||||||
impl<'a> DiffMachine<'a> {
|
impl<'a> DiffMachine<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
// pub fn new(bump: &'a Bump) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
lifecycle_events: VecDeque::new(),
|
lifecycle_events: VecDeque::new(),
|
||||||
change_list: EditMachine::new(),
|
change_list: EditMachine::new(),
|
||||||
|
@ -265,8 +262,13 @@ impl<'a> DiffMachine<'a> {
|
||||||
let id = uuid::Uuid::new_v4();
|
let id = uuid::Uuid::new_v4();
|
||||||
*component.stable_addr.as_ref().borrow_mut() = Some(id);
|
*component.stable_addr.as_ref().borrow_mut() = Some(id);
|
||||||
self.change_list.save_known_root(id);
|
self.change_list.save_known_root(id);
|
||||||
|
|
||||||
|
let caller = Rc::downgrade(&component.caller);
|
||||||
|
// let broken_caller: Weak<dyn Fn(Context) -> DomTree + 'static> =
|
||||||
|
// unsafe { std::mem::transmute(caller) };
|
||||||
self.lifecycle_events.push_back(LifeCycleEvent::Mount {
|
self.lifecycle_events.push_back(LifeCycleEvent::Mount {
|
||||||
caller: component.caller.clone(),
|
caller,
|
||||||
|
// caller: broken_caller,
|
||||||
id,
|
id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,38 +23,42 @@ pub type EditList<'src> = Vec<Edit<'src>>;
|
||||||
|
|
||||||
/// The `Edit` represents a single modifcation of the renderer tree.
|
/// The `Edit` represents a single modifcation of the renderer tree.
|
||||||
/// todo@ jon: allow serde to be optional
|
/// todo@ jon: allow serde to be optional
|
||||||
|
/// todo @jon, go through and make certain fields static. tag names should be known at compile time
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum Edit<'d> {
|
pub enum Edit<'src_bump> {
|
||||||
// ========================================================
|
// ========================================================
|
||||||
// Common Ops: The most common operation types
|
// Common Ops: The most common operation types
|
||||||
// ========================================================
|
// ========================================================
|
||||||
SetText {
|
SetText {
|
||||||
text: &'d str,
|
text: &'src_bump str,
|
||||||
},
|
},
|
||||||
SetClass {
|
SetClass {
|
||||||
class_name: &'d str,
|
class_name: &'src_bump str,
|
||||||
},
|
},
|
||||||
CreateTextNode {
|
CreateTextNode {
|
||||||
text: &'d str,
|
text: &'src_bump str,
|
||||||
},
|
},
|
||||||
CreateElement {
|
CreateElement {
|
||||||
tag_name: &'d str,
|
// todo - make static?
|
||||||
|
tag_name: &'src_bump str,
|
||||||
},
|
},
|
||||||
CreateElementNs {
|
CreateElementNs {
|
||||||
tag_name: &'d str,
|
// todo - make static?
|
||||||
ns: &'d str,
|
tag_name: &'src_bump str,
|
||||||
|
// todo - make static?
|
||||||
|
ns: &'src_bump str,
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
// Attributes
|
// Attributes
|
||||||
// ========================================================
|
// ========================================================
|
||||||
SetAttribute {
|
SetAttribute {
|
||||||
name: &'d str,
|
name: &'src_bump str,
|
||||||
value: &'d str,
|
value: &'src_bump str,
|
||||||
},
|
},
|
||||||
RemoveAttribute {
|
RemoveAttribute {
|
||||||
name: &'d str,
|
name: &'src_bump str,
|
||||||
},
|
},
|
||||||
RemoveChild {
|
RemoveChild {
|
||||||
n: u32,
|
n: u32,
|
||||||
|
@ -64,17 +68,20 @@ pub enum Edit<'d> {
|
||||||
// Event Listeners: Event types and IDs used to update the VDOM
|
// Event Listeners: Event types and IDs used to update the VDOM
|
||||||
// ============================================================
|
// ============================================================
|
||||||
NewListener {
|
NewListener {
|
||||||
event: &'d str,
|
// todo - make static?
|
||||||
|
event: &'src_bump str,
|
||||||
scope: ScopeIdx,
|
scope: ScopeIdx,
|
||||||
id: usize,
|
id: usize,
|
||||||
},
|
},
|
||||||
UpdateListener {
|
UpdateListener {
|
||||||
event: &'d str,
|
// todo - make static?
|
||||||
|
event: &'src_bump str,
|
||||||
scope: ScopeIdx,
|
scope: ScopeIdx,
|
||||||
id: usize,
|
id: usize,
|
||||||
},
|
},
|
||||||
RemoveListener {
|
RemoveListener {
|
||||||
event: &'d str,
|
// todo - make static?
|
||||||
|
event: &'src_bump str,
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
@ -124,22 +131,28 @@ pub enum Edit<'d> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EditMachine<'src> {
|
/// The edit machine represents a stream of differences between two component trees.
|
||||||
|
///
|
||||||
|
/// This struct is interesting in that it keeps track of differences by borrowing
|
||||||
|
/// from the source rather than writing to a new buffer. This means that the virtual dom
|
||||||
|
/// *cannot* be updated while this machine is in existence without "unsafe".
|
||||||
|
///
|
||||||
|
/// This unsafety is handled by methods on the virtual dom and is not exposed via lib code.
|
||||||
|
pub struct EditMachine<'lock> {
|
||||||
pub traversal: Traversal,
|
pub traversal: Traversal,
|
||||||
next_temporary: u32,
|
next_temporary: u32,
|
||||||
forcing_new_listeners: bool,
|
forcing_new_listeners: bool,
|
||||||
pub emitter: EditList<'src>,
|
|
||||||
|
pub emitter: EditList<'lock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> EditMachine<'b> {
|
impl<'lock> EditMachine<'lock> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
// pub fn new(_bump: &'b bumpalo::Bump) -> Self {
|
|
||||||
// todo: see if bumpalo is needed for edit list
|
|
||||||
Self {
|
Self {
|
||||||
traversal: Traversal::new(),
|
traversal: Traversal::new(),
|
||||||
next_temporary: 0,
|
next_temporary: 0,
|
||||||
forcing_new_listeners: false,
|
forcing_new_listeners: false,
|
||||||
emitter: EditList::<'b>::default(),
|
emitter: EditList::<'lock>::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +160,7 @@ impl<'b> EditMachine<'b> {
|
||||||
// ===================================
|
// ===================================
|
||||||
// Traversal Methods
|
// Traversal Methods
|
||||||
// ===================================
|
// ===================================
|
||||||
impl<'b> EditMachine<'b> {
|
impl<'src> EditMachine<'src> {
|
||||||
pub fn go_down(&mut self) {
|
pub fn go_down(&mut self) {
|
||||||
self.traversal.down();
|
self.traversal.down();
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,8 @@ impl Scope {
|
||||||
// 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.
|
||||||
// This should never happen, but is a good check to keep around
|
// This should never happen, but is a good check to keep around
|
||||||
pub fn new<'creator_node>(
|
pub fn new<'creator_node>(
|
||||||
|
// pub fn new(
|
||||||
|
// caller: Weak<dyn Fn(Context) -> DomTree + 'static>,
|
||||||
caller: Weak<dyn Fn(Context) -> DomTree + 'creator_node>,
|
caller: Weak<dyn Fn(Context) -> DomTree + 'creator_node>,
|
||||||
myidx: ScopeIdx,
|
myidx: ScopeIdx,
|
||||||
parent: Option<ScopeIdx>,
|
parent: Option<ScopeIdx>,
|
||||||
|
@ -106,6 +108,7 @@ impl Scope {
|
||||||
let broken_caller: Weak<dyn Fn(Context) -> DomTree + 'static> =
|
let broken_caller: Weak<dyn Fn(Context) -> DomTree + 'static> =
|
||||||
unsafe { std::mem::transmute(caller) };
|
unsafe { std::mem::transmute(caller) };
|
||||||
|
|
||||||
|
// let broken_caller = caller;
|
||||||
Self {
|
Self {
|
||||||
caller: broken_caller,
|
caller: broken_caller,
|
||||||
hook_arena: typed_arena::Arena::new(),
|
hook_arena: typed_arena::Arena::new(),
|
||||||
|
|
|
@ -101,6 +101,9 @@ impl VirtualDom {
|
||||||
component.run();
|
component.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get raw pointer to the arena
|
||||||
|
let very_unsafe_components = &mut self.components as *mut generational_arena::Arena<Scope>;
|
||||||
|
|
||||||
{
|
{
|
||||||
let component = self
|
let component = self
|
||||||
.components
|
.components
|
||||||
|
@ -110,36 +113,47 @@ impl VirtualDom {
|
||||||
diff_machine.diff_node(component.old_frame(), component.new_frame());
|
diff_machine.diff_node(component.old_frame(), component.new_frame());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'render: loop {
|
// chew down the the lifecycle events until all dirty nodes are computed
|
||||||
// for event in &mut diff_machine.lifecycle_events.drain(..) {
|
while let Some(event) = diff_machine.lifecycle_events.pop_front() {
|
||||||
// log::debug!("event is {:#?}", event);
|
match event {
|
||||||
// match event {
|
// A new component has been computed from the diffing algorithm
|
||||||
// LifeCycleEvent::Mount { caller, id } => {
|
// create a new component in the arena, run it, move the diffing machine to this new spot, and then diff it
|
||||||
// diff_machine.change_list.load_known_root(id);
|
// this will flood the lifecycle queue with new updates
|
||||||
// let idx = self
|
LifeCycleEvent::Mount { caller, id } => {
|
||||||
// .components
|
log::debug!("Mounting a new component");
|
||||||
// .insert_with(|f| create_scoped(caller, f, None));
|
diff_machine.change_list.load_known_root(id);
|
||||||
// // .insert_with(|f| create_scoped(caller, props, myidx, parent));
|
|
||||||
// }
|
|
||||||
// LifeCycleEvent::PropsChanged => {
|
|
||||||
// //
|
|
||||||
// break 'render;
|
|
||||||
// }
|
|
||||||
// LifeCycleEvent::SameProps => {
|
|
||||||
// //
|
|
||||||
// break 'render;
|
|
||||||
// }
|
|
||||||
// LifeCycleEvent::Remove => {
|
|
||||||
// //
|
|
||||||
// break 'render;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if diff_machine.lifecycle_events.is_empty() {
|
// We're modifying the component arena while holding onto references into the assoiated bump arenas of its children
|
||||||
// break 'render;
|
// those references are stable, even if the component arena moves around in memory, thanks to the bump arenas.
|
||||||
// }
|
// However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime.
|
||||||
// }
|
unsafe {
|
||||||
|
let p = &mut *(very_unsafe_components);
|
||||||
|
|
||||||
|
// todo, hook up the parent/child indexes properly
|
||||||
|
let idx = p.insert_with(|f| Scope::new(caller, f, None));
|
||||||
|
let c = p.get_mut(idx).unwrap();
|
||||||
|
c.run();
|
||||||
|
diff_machine.diff_node(c.old_frame(), c.new_frame());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LifeCycleEvent::PropsChanged => {
|
||||||
|
//
|
||||||
|
// break 'render;
|
||||||
|
}
|
||||||
|
LifeCycleEvent::SameProps => {
|
||||||
|
//
|
||||||
|
// break 'render;
|
||||||
|
}
|
||||||
|
LifeCycleEvent::Remove => {
|
||||||
|
//
|
||||||
|
// break 'render;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
// break 'render;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
let edits: Vec<Edit<'s>> = diff_machine.consume();
|
let edits: Vec<Edit<'s>> = diff_machine.consume();
|
||||||
Ok(edits)
|
Ok(edits)
|
||||||
|
|
Loading…
Reference in a new issue