Feat: props now autoderives its own trait

This commit is contained in:
Jonathan Kelley 2021-03-12 15:41:36 -05:00
parent d4f1ceaffb
commit b3c96a5996
10 changed files with 123 additions and 83 deletions

View 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,
}

View file

@ -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)]

View file

@ -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 {
todo!()
// ctx.render(rsx! {

View file

@ -24,10 +24,3 @@ static SomeComponent: FC<ExampleProps> = |ctx, _props| {
};
fn main() {}
impl Properties for ExampleProps {
type Builder = ExamplePropsBuilder<((),)>;
fn builder() -> Self::Builder {
ExampleProps::builder()
}
}

View file

@ -1,6 +1,6 @@
use dioxus_core_macro::Props;
use dioxus_core::prelude::*;
#[derive(Debug, Props)]
#[derive(Debug, PartialEq, Props)]
struct SomeProps {
a: i32,
@ -9,12 +9,8 @@ struct SomeProps {
b: Option<i32>,
}
// have we committed to the trait style yet?
fn main() {
let g: SomeProps = SomeProps::builder().a(10).b(10).build();
let _r = g.b.unwrap_or_else(|| 10);
}
fn auto_into_some() {}

View file

@ -23,11 +23,3 @@ static Example: FC<SomeProps> = |ctx, _props| {
</div>
})
};
// toodo: derive this
impl Properties for SomeProps {
type Builder = SomePropsBuilder<((),)>;
fn builder() -> Self::Builder {
SomeProps::builder()
}
}

View file

@ -42,7 +42,7 @@ use std::{
cell::{RefCell, RefMut},
cmp::Ordering,
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
@ -62,11 +62,9 @@ pub struct DiffMachine<'a> {
pub diffed: FxHashSet<ScopeIdx>,
pub lifecycle_events: VecDeque<LifeCycleEvent<'a>>,
}
// #[derive(Debug)]
pub enum LifeCycleEvent<'a> {
Mount {
caller: Rc<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
caller: Weak<dyn for<'r> Fn(Context<'r>) -> DomTree + 'a>,
id: Uuid,
},
PropsChanged,
@ -76,7 +74,6 @@ pub enum LifeCycleEvent<'a> {
impl<'a> DiffMachine<'a> {
pub fn new() -> Self {
// pub fn new(bump: &'a Bump) -> Self {
Self {
lifecycle_events: VecDeque::new(),
change_list: EditMachine::new(),
@ -265,8 +262,13 @@ impl<'a> DiffMachine<'a> {
let id = uuid::Uuid::new_v4();
*component.stable_addr.as_ref().borrow_mut() = Some(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 {
caller: component.caller.clone(),
caller,
// caller: broken_caller,
id,
});
}

View file

@ -23,38 +23,42 @@ pub type EditList<'src> = Vec<Edit<'src>>;
/// The `Edit` represents a single modifcation of the renderer tree.
/// 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)]
#[serde(tag = "type")]
pub enum Edit<'d> {
pub enum Edit<'src_bump> {
// ========================================================
// Common Ops: The most common operation types
// ========================================================
SetText {
text: &'d str,
text: &'src_bump str,
},
SetClass {
class_name: &'d str,
class_name: &'src_bump str,
},
CreateTextNode {
text: &'d str,
text: &'src_bump str,
},
CreateElement {
tag_name: &'d str,
// todo - make static?
tag_name: &'src_bump str,
},
CreateElementNs {
tag_name: &'d str,
ns: &'d str,
// todo - make static?
tag_name: &'src_bump str,
// todo - make static?
ns: &'src_bump str,
},
// ========================================================
// Attributes
// ========================================================
SetAttribute {
name: &'d str,
value: &'d str,
name: &'src_bump str,
value: &'src_bump str,
},
RemoveAttribute {
name: &'d str,
name: &'src_bump str,
},
RemoveChild {
n: u32,
@ -64,17 +68,20 @@ pub enum Edit<'d> {
// Event Listeners: Event types and IDs used to update the VDOM
// ============================================================
NewListener {
event: &'d str,
// todo - make static?
event: &'src_bump str,
scope: ScopeIdx,
id: usize,
},
UpdateListener {
event: &'d str,
// todo - make static?
event: &'src_bump str,
scope: ScopeIdx,
id: usize,
},
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,
next_temporary: u32,
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(_bump: &'b bumpalo::Bump) -> Self {
// todo: see if bumpalo is needed for edit list
Self {
traversal: Traversal::new(),
next_temporary: 0,
forcing_new_listeners: false,
emitter: EditList::<'b>::default(),
emitter: EditList::<'lock>::default(),
}
}
}
@ -147,7 +160,7 @@ impl<'b> EditMachine<'b> {
// ===================================
// Traversal Methods
// ===================================
impl<'b> EditMachine<'b> {
impl<'src> EditMachine<'src> {
pub fn go_down(&mut self) {
self.traversal.down();
}

View file

@ -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.
// This should never happen, but is a good check to keep around
pub fn new<'creator_node>(
// pub fn new(
// caller: Weak<dyn Fn(Context) -> DomTree + 'static>,
caller: Weak<dyn Fn(Context) -> DomTree + 'creator_node>,
myidx: ScopeIdx,
parent: Option<ScopeIdx>,
@ -106,6 +108,7 @@ impl Scope {
let broken_caller: Weak<dyn Fn(Context) -> DomTree + 'static> =
unsafe { std::mem::transmute(caller) };
// let broken_caller = caller;
Self {
caller: broken_caller,
hook_arena: typed_arena::Arena::new(),

View file

@ -101,6 +101,9 @@ impl VirtualDom {
component.run();
}
// get raw pointer to the arena
let very_unsafe_components = &mut self.components as *mut generational_arena::Arena<Scope>;
{
let component = self
.components
@ -110,36 +113,47 @@ impl VirtualDom {
diff_machine.diff_node(component.old_frame(), component.new_frame());
}
// 'render: loop {
// for event in &mut diff_machine.lifecycle_events.drain(..) {
// log::debug!("event is {:#?}", event);
// match event {
// LifeCycleEvent::Mount { caller, id } => {
// diff_machine.change_list.load_known_root(id);
// let idx = self
// .components
// .insert_with(|f| create_scoped(caller, f, None));
// // .insert_with(|f| create_scoped(caller, props, myidx, parent));
// }
// LifeCycleEvent::PropsChanged => {
// //
// break 'render;
// }
// LifeCycleEvent::SameProps => {
// //
// break 'render;
// }
// LifeCycleEvent::Remove => {
// //
// break 'render;
// }
// }
// }
// chew down the the lifecycle events until all dirty nodes are computed
while let Some(event) = diff_machine.lifecycle_events.pop_front() {
match event {
// A new component has been computed from the diffing algorithm
// create a new component in the arena, run it, move the diffing machine to this new spot, and then diff it
// this will flood the lifecycle queue with new updates
LifeCycleEvent::Mount { caller, id } => {
log::debug!("Mounting a new component");
diff_machine.change_list.load_known_root(id);
// if diff_machine.lifecycle_events.is_empty() {
// break 'render;
// }
// }
// We're modifying the component arena while holding onto references into the assoiated bump arenas of its children
// 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();
Ok(edits)