2022-12-17 03:54:33 +00:00
use crate ::any_props ::AnyProps ;
2023-01-02 20:40:25 +00:00
use crate ::innerlude ::{ BorrowedAttributeValue , VComponent , VPlaceholder , VText } ;
2022-10-28 04:58:47 +00:00
use crate ::mutations ::Mutation ;
2022-11-02 01:42:29 +00:00
use crate ::mutations ::Mutation ::* ;
use crate ::nodes ::VNode ;
2022-11-03 08:24:20 +00:00
use crate ::nodes ::{ DynamicNode , TemplateNode } ;
2022-11-09 03:39:37 +00:00
use crate ::virtual_dom ::VirtualDom ;
2022-12-20 01:28:44 +00:00
use crate ::{ AttributeValue , ElementId , RenderReturn , ScopeId , SuspenseContext , Template } ;
2022-12-13 02:31:30 +00:00
use std ::cell ::Cell ;
2022-12-22 17:36:38 +00:00
use std ::iter ::Peekable ;
2022-12-13 02:31:30 +00:00
use std ::rc ::Rc ;
use TemplateNode ::* ;
2022-10-28 04:58:47 +00:00
2022-12-22 17:36:38 +00:00
fn sort_bfs ( paths : & [ & 'static [ u8 ] ] ) -> Vec < ( usize , & 'static [ u8 ] ) > {
let mut with_indecies = paths . iter ( ) . copied ( ) . enumerate ( ) . collect ::< Vec < _ > > ( ) ;
with_indecies . sort_unstable_by ( | ( _ , a ) , ( _ , b ) | {
let mut a = a . iter ( ) ;
let mut b = b . iter ( ) ;
loop {
match ( a . next ( ) , b . next ( ) ) {
( Some ( a ) , Some ( b ) ) = > {
if a ! = b {
return a . cmp ( b ) ;
}
}
// The shorter path goes first
( Some ( _ ) , None ) = > return std ::cmp ::Ordering ::Less ,
( None , Some ( _ ) ) = > return std ::cmp ::Ordering ::Greater ,
( None , None ) = > return std ::cmp ::Ordering ::Equal ,
}
}
} ) ;
with_indecies
}
#[ test ]
fn sorting ( ) {
let r : [ ( usize , & [ u8 ] ) ; 5 ] = [
( 0 , & [ 0 , 1 ] ) ,
( 1 , & [ 0 , 2 ] ) ,
( 2 , & [ 1 , 0 ] ) ,
( 4 , & [ 1 , 1 ] ) ,
( 3 , & [ 1 , 2 ] ) ,
] ;
assert_eq! (
sort_bfs ( & [ & [ 0 , 1 , ] , & [ 0 , 2 , ] , & [ 1 , 0 , ] , & [ 1 , 2 , ] , & [ 1 , 1 , ] , ] ) ,
r
) ;
assert! ( matches! ( & [ 0 ] , & [ _ , .. ] ) )
}
2022-11-29 21:31:04 +00:00
impl < ' b > VirtualDom {
2022-11-22 01:00:34 +00:00
/// Create a new template [`VNode`] and write it to the [`Mutations`] buffer.
///
/// This method pushes the ScopeID to the internal scopestack and returns the number of nodes created.
2022-11-23 03:59:56 +00:00
pub ( crate ) fn create_scope ( & mut self , scope : ScopeId , template : & ' b VNode < ' b > ) -> usize {
2022-11-09 18:58:11 +00:00
self . scope_stack . push ( scope ) ;
2022-11-23 03:59:56 +00:00
let out = self . create ( template ) ;
2022-11-09 18:58:11 +00:00
self . scope_stack . pop ( ) ;
out
}
2022-10-28 04:58:47 +00:00
/// Create this template and write its mutations
2022-12-13 02:31:30 +00:00
pub ( crate ) fn create ( & mut self , node : & ' b VNode < ' b > ) -> usize {
2022-12-22 22:54:49 +00:00
// check for a overriden template
#[ cfg(debug_assertions) ]
{
let ( path , byte_index ) = node . template . get ( ) . name . rsplit_once ( ':' ) . unwrap ( ) ;
if let Some ( template ) = self
. templates
. get ( path )
. and_then ( | map | map . get ( & byte_index . parse ( ) . unwrap ( ) ) )
{
node . template . set ( * template ) ;
}
}
2022-12-21 18:50:48 +00:00
// Intialize the root nodes slice
node . root_ids
. intialize ( vec! [ ElementId ( 0 ) ; node . template . get ( ) . roots . len ( ) ] . into_boxed_slice ( ) ) ;
2022-11-09 18:58:11 +00:00
// The best renderers will have templates prehydrated and registered
2022-10-28 04:58:47 +00:00
// Just in case, let's create the template using instructions anyways
2022-12-20 01:28:44 +00:00
if ! self . templates . contains_key ( & node . template . get ( ) . name ) {
self . register_template ( node . template . get ( ) ) ;
2022-10-28 04:58:47 +00:00
}
2022-12-13 02:31:30 +00:00
// we know that this will generate at least one mutation per node
2022-12-20 01:28:44 +00:00
self . mutations
. edits
. reserve ( node . template . get ( ) . roots . len ( ) ) ;
2022-12-13 02:31:30 +00:00
2022-11-09 18:58:11 +00:00
// Walk the roots, creating nodes and assigning IDs
2022-12-22 17:36:38 +00:00
// nodes in an iterator of ((dynamic_node_index, sorted_index), path)
2022-10-28 04:58:47 +00:00
// todo: adjust dynamic nodes to be in the order of roots and then leaves (ie BFS)
2022-12-22 17:36:38 +00:00
#[ cfg(not(debug_assertions)) ]
let ( mut attrs , mut nodes ) = (
node . template
. get ( )
. attr_paths
. iter ( )
. copied ( )
. enumerate ( )
. peekable ( ) ,
node . template
. get ( )
. node_paths
. iter ( )
. copied ( )
. enumerate ( )
. map ( | ( i , path ) | ( ( i , i ) , path ) )
. peekable ( ) ,
) ;
// If this is a debug build, we need to check that the paths are in the correct order because hot reloading can cause scrambled states
#[ cfg(debug_assertions) ]
let ( attrs_sorted , nodes_sorted ) = {
(
sort_bfs ( node . template . get ( ) . attr_paths ) ,
sort_bfs ( node . template . get ( ) . node_paths ) ,
)
} ;
#[ cfg(debug_assertions) ]
let ( mut attrs , mut nodes ) = {
(
attrs_sorted . into_iter ( ) . peekable ( ) ,
nodes_sorted
. iter ( )
. copied ( )
. enumerate ( )
. map ( | ( i , ( id , path ) ) | ( ( id , i ) , path ) )
. peekable ( ) ,
)
} ;
2022-12-13 02:31:30 +00:00
node . template
2022-12-20 01:28:44 +00:00
. get ( )
2022-12-13 02:31:30 +00:00
. roots
. iter ( )
. enumerate ( )
. map ( | ( idx , root ) | match root {
2022-12-17 06:39:27 +00:00
DynamicText { id } | Dynamic { id } = > {
nodes . next ( ) . unwrap ( ) ;
self . write_dynamic_root ( node , * id )
}
2022-12-22 17:36:38 +00:00
Element { .. } = > {
#[ cfg(not(debug_assertions)) ]
let id = self . write_element_root ( node , idx , & mut attrs , & mut nodes , & [ ] ) ;
#[ cfg(debug_assertions) ]
let id =
self . write_element_root ( node , idx , & mut attrs , & mut nodes , & nodes_sorted ) ;
id
}
2022-12-13 02:31:30 +00:00
Text { .. } = > self . write_static_text_root ( node , idx ) ,
} )
. sum ( )
}
2022-11-16 07:31:23 +00:00
2022-12-13 02:31:30 +00:00
fn write_static_text_root ( & mut self , node : & VNode , idx : usize ) -> usize {
// Simply just load the template root, no modifications needed
self . load_template_root ( node , idx ) ;
2022-10-28 04:58:47 +00:00
2022-12-13 02:31:30 +00:00
// Text producs just one node on the stack
1
}
fn write_dynamic_root ( & mut self , template : & ' b VNode < ' b > , idx : usize ) -> usize {
use DynamicNode ::* ;
match & template . dynamic_nodes [ idx ] {
2022-12-22 17:36:38 +00:00
node @ Component { .. } | node @ Fragment ( _ ) = > {
self . create_dynamic_node ( template , node , idx )
}
2022-12-13 02:31:30 +00:00
Placeholder ( VPlaceholder { id } ) = > {
let id = self . set_slot ( template , id , idx ) ;
self . mutations . push ( CreatePlaceholder { id } ) ;
1
}
Text ( VText { id , value } ) = > {
let id = self . set_slot ( template , id , idx ) ;
self . create_static_text ( value , id ) ;
1
}
}
}
fn create_static_text ( & mut self , value : & str , id : ElementId ) {
// Safety: we promise not to re-alias this text later on after committing it to the mutation
let unbounded_text : & str = unsafe { std ::mem ::transmute ( value ) } ;
self . mutations . push ( CreateTextNode {
value : unbounded_text ,
id ,
} ) ;
}
/// We write all the descndent data for this element
///
/// Elements can contain other nodes - and those nodes can be dynamic or static
///
/// We want to make sure we write these nodes while on top of the root
fn write_element_root (
& mut self ,
template : & ' b VNode < ' b > ,
root_idx : usize ,
2022-12-22 17:36:38 +00:00
dynamic_attrs : & mut Peekable < impl Iterator < Item = ( usize , & 'static [ u8 ] ) > > ,
dynamic_nodes_iter : & mut Peekable < impl Iterator < Item = ( ( usize , usize ) , & 'static [ u8 ] ) > > ,
dynamic_nodes : & [ ( usize , & 'static [ u8 ] ) ] ,
2022-12-13 02:31:30 +00:00
) -> usize {
// Load the template root and get the ID for the node on the stack
let root_on_stack = self . load_template_root ( template , root_idx ) ;
// Write all the attributes below this root
2022-12-22 17:36:38 +00:00
self . write_attrs_on_root ( dynamic_attrs , root_idx as u8 , root_on_stack , template ) ;
2022-12-13 02:31:30 +00:00
// Load in all of the placeholder or dynamic content under this root too
2022-12-22 17:36:38 +00:00
self . load_placeholders ( dynamic_nodes_iter , dynamic_nodes , root_idx as u8 , template ) ;
2022-12-13 02:31:30 +00:00
1
}
2022-11-09 04:06:39 +00:00
2022-12-13 02:31:30 +00:00
/// Load all of the placeholder nodes for descendents of this root node
///
/// ```rust, ignore
/// rsx! {
/// div {
/// // This is a placeholder
/// some_value,
///
/// // Load this too
/// "{some_text}"
/// }
/// }
/// ```
2022-12-22 17:36:38 +00:00
#[ allow(unused) ]
2022-12-13 02:31:30 +00:00
fn load_placeholders (
& mut self ,
2022-12-22 17:36:38 +00:00
dynamic_nodes_iter : & mut Peekable < impl Iterator < Item = ( ( usize , usize ) , & 'static [ u8 ] ) > > ,
dynamic_nodes : & [ ( usize , & 'static [ u8 ] ) ] ,
root_idx : u8 ,
2022-12-13 02:31:30 +00:00
template : & ' b VNode < ' b > ,
) {
2022-12-22 17:36:38 +00:00
let ( start , end ) = match collect_dyn_node_range ( dynamic_nodes_iter , root_idx ) {
2022-12-13 02:31:30 +00:00
Some ( ( a , b ) ) = > ( a , b ) ,
2022-12-17 06:44:07 +00:00
None = > return ,
2022-12-13 02:31:30 +00:00
} ;
2022-12-22 17:36:38 +00:00
// If hot reloading is enabled, we need to map the sorted index to the original index of the dynamic node. If it is disabled, we can just use the sorted index
#[ cfg(not(debug_assertions)) ]
let reversed_iter = ( start ..= end ) . rev ( ) ;
#[ cfg(debug_assertions) ]
let reversed_iter = ( start ..= end )
. rev ( )
. map ( | sorted_index | dynamic_nodes [ sorted_index ] . 0 ) ;
for idx in reversed_iter {
2022-12-13 02:31:30 +00:00
let m = self . create_dynamic_node ( template , & template . dynamic_nodes [ idx ] , idx ) ;
if m > 0 {
// The path is one shorter because the top node is the root
2022-12-20 01:28:44 +00:00
let path = & template . template . get ( ) . node_paths [ idx ] [ 1 .. ] ;
2022-12-13 02:31:30 +00:00
self . mutations . push ( ReplacePlaceholder { m , path } ) ;
}
}
}
2022-11-09 04:06:39 +00:00
2022-12-13 02:31:30 +00:00
fn write_attrs_on_root (
& mut self ,
2022-12-22 17:36:38 +00:00
attrs : & mut Peekable < impl Iterator < Item = ( usize , & 'static [ u8 ] ) > > ,
root_idx : u8 ,
2022-12-13 02:31:30 +00:00
root : ElementId ,
node : & VNode ,
) {
2022-12-22 21:09:58 +00:00
while let Some ( ( mut attr_id , path ) ) =
attrs . next_if ( | ( _ , p ) | p . first ( ) . copied ( ) = = Some ( root_idx ) )
{
2022-12-13 02:31:30 +00:00
let id = self . assign_static_node_as_dynamic ( path , root , node , attr_id ) ;
loop {
self . write_attribute ( & node . dynamic_attrs [ attr_id ] , id ) ;
// Only push the dynamic attributes forward if they match the current path (same element)
match attrs . next_if ( | ( _ , p ) | * p = = path ) {
Some ( ( next_attr_id , _ ) ) = > attr_id = next_attr_id ,
None = > break ,
2022-11-16 19:48:47 +00:00
}
2022-12-13 02:31:30 +00:00
}
2022-10-28 04:58:47 +00:00
}
2022-12-13 02:31:30 +00:00
}
2023-01-02 20:40:25 +00:00
fn write_attribute ( & mut self , attribute : & ' b crate ::Attribute < ' b > , id : ElementId ) {
2022-12-13 02:31:30 +00:00
// Make sure we set the attribute's associated id
attribute . mounted_element . set ( id ) ;
// Safety: we promise not to re-alias this text later on after committing it to the mutation
2022-12-17 03:54:33 +00:00
let unbounded_name : & str = unsafe { std ::mem ::transmute ( attribute . name ) } ;
2022-12-13 02:31:30 +00:00
2022-12-17 09:55:18 +00:00
match & attribute . value {
AttributeValue ::Listener ( _ ) = > {
self . mutations . push ( NewEventListener {
// all listeners start with "on"
name : & unbounded_name [ 2 .. ] ,
id ,
} )
}
_ = > {
// Safety: we promise not to re-alias this text later on after committing it to the mutation
2023-01-02 20:40:25 +00:00
let value : BorrowedAttributeValue < ' b > = ( & attribute . value ) . into ( ) ;
let unbounded_value = unsafe { std ::mem ::transmute ( value ) } ;
2022-12-17 09:55:18 +00:00
self . mutations . push ( SetAttribute {
name : unbounded_name ,
value : unbounded_value ,
ns : attribute . namespace ,
id ,
} )
}
}
2022-12-13 02:31:30 +00:00
}
fn load_template_root ( & mut self , template : & VNode , root_idx : usize ) -> ElementId {
// Get an ID for this root since it's a real root
let this_id = self . next_root ( template , root_idx ) ;
2022-12-21 18:50:48 +00:00
template . root_ids . set ( root_idx , this_id ) ;
2022-12-13 02:31:30 +00:00
self . mutations . push ( LoadTemplate {
2022-12-20 01:28:44 +00:00
name : template . template . get ( ) . name ,
2022-12-13 02:31:30 +00:00
index : root_idx ,
id : this_id ,
} ) ;
2022-10-28 04:58:47 +00:00
2022-12-13 02:31:30 +00:00
this_id
}
/// We have some dynamic attributes attached to a some node
///
/// That node needs to be loaded at runtime, so we need to give it an ID
///
/// If the node in question is on the stack, we just return that ID
///
/// If the node is not on the stack, we create a new ID for it and assign it
fn assign_static_node_as_dynamic (
& mut self ,
path : & 'static [ u8 ] ,
this_id : ElementId ,
template : & VNode ,
attr_id : usize ,
) -> ElementId {
if path . len ( ) = = 1 {
return this_id ;
}
// if attribute is on a root node, then we've already created the element
// Else, it's deep in the template and we should create a new id for it
2022-12-20 01:28:44 +00:00
let id = self . next_element ( template , template . template . get ( ) . attr_paths [ attr_id ] ) ;
2022-12-13 02:31:30 +00:00
self . mutations . push ( Mutation ::AssignId {
path : & path [ 1 .. ] ,
id ,
} ) ;
2022-10-28 04:58:47 +00:00
2022-12-13 02:31:30 +00:00
id
2022-10-28 04:58:47 +00:00
}
2022-11-22 01:00:34 +00:00
/// Insert a new template into the VirtualDom's template registry
2022-12-22 22:38:07 +00:00
pub ( crate ) fn register_template_first_byte_index ( & mut self , mut template : Template < 'static > ) {
2022-11-23 05:32:26 +00:00
// First, make sure we mark the template as seen, regardless if we process it
2022-12-22 22:38:07 +00:00
let ( path , _ ) = template . name . rsplit_once ( ':' ) . unwrap ( ) ;
if let Some ( ( _ , old_template ) ) = self
. templates
. entry ( path )
. or_default ( )
. iter_mut ( )
. min_by_key ( | ( byte_index , _ ) | * * byte_index )
{
// the byte index of the hot reloaded template could be different
template . name = old_template . name ;
* old_template = template ;
} else {
2022-12-22 22:54:49 +00:00
// This is a template without any current instances
self . templates
. entry ( path )
. or_default ( )
. insert ( usize ::MAX , template ) ;
2022-12-22 22:38:07 +00:00
}
// If it's all dynamic nodes, then we don't need to register it
if ! template . is_completely_dynamic ( ) {
self . mutations . templates . push ( template ) ;
}
}
2022-11-22 01:00:34 +00:00
/// Insert a new template into the VirtualDom's template registry
2022-12-22 22:54:49 +00:00
pub ( crate ) fn register_template ( & mut self , mut template : Template < 'static > ) {
2022-11-23 05:32:26 +00:00
// First, make sure we mark the template as seen, regardless if we process it
2022-12-22 22:38:07 +00:00
let ( path , byte_index ) = template . name . rsplit_once ( ':' ) . unwrap ( ) ;
let byte_index = byte_index . parse ::< usize > ( ) . unwrap ( ) ;
2022-12-22 22:54:49 +00:00
// if hot reloading is enabled, then we need to check for a template that has overriten this one
#[ cfg(debug_assertions) ]
if let Some ( mut new_template ) = self
. templates
. get_mut ( path )
. and_then ( | map | map . remove ( & usize ::MAX ) )
{
// the byte index of the hot reloaded template could be different
new_template . name = template . name ;
template = new_template ;
}
2022-11-23 05:32:26 +00:00
self . templates
2022-12-22 22:38:07 +00:00
. entry ( path )
. or_default ( )
. insert ( byte_index , template ) ;
2022-11-23 05:32:26 +00:00
// If it's all dynamic nodes, then we don't need to register it
2022-12-20 01:28:44 +00:00
if ! template . is_completely_dynamic ( ) {
self . mutations . templates . push ( template ) ;
2022-11-23 05:32:26 +00:00
}
2022-10-28 04:58:47 +00:00
}
2022-11-23 03:59:56 +00:00
pub ( crate ) fn create_dynamic_node (
2022-10-28 04:58:47 +00:00
& mut self ,
2022-11-23 03:59:56 +00:00
template : & ' b VNode < ' b > ,
node : & ' b DynamicNode < ' b > ,
2022-11-03 08:24:20 +00:00
idx : usize ,
2022-10-28 04:58:47 +00:00
) -> usize {
2022-11-22 01:00:34 +00:00
use DynamicNode ::* ;
match node {
2022-11-23 03:59:56 +00:00
Text ( text ) = > self . create_dynamic_text ( template , text , idx ) ,
2022-12-24 00:43:19 +00:00
Placeholder ( place ) = > self . create_placeholder ( place , template , idx ) ,
2022-11-23 03:59:56 +00:00
Component ( component ) = > self . create_component_node ( template , component , idx ) ,
2022-12-24 00:33:15 +00:00
Fragment ( frag ) = > frag . iter ( ) . map ( | child | self . create ( child ) ) . sum ( ) ,
2022-11-22 01:00:34 +00:00
}
}
2022-11-02 01:42:29 +00:00
2022-11-23 03:59:56 +00:00
fn create_dynamic_text (
2022-11-22 01:00:34 +00:00
& mut self ,
2022-11-23 03:59:56 +00:00
template : & ' b VNode < ' b > ,
text : & ' b VText < ' b > ,
2022-11-22 01:00:34 +00:00
idx : usize ,
) -> usize {
// Allocate a dynamic element reference for this text node
2022-12-20 01:28:44 +00:00
let new_id = self . next_element ( template , template . template . get ( ) . node_paths [ idx ] ) ;
2022-11-16 00:05:22 +00:00
2022-11-22 01:00:34 +00:00
// Make sure the text node is assigned to the correct element
2022-12-13 02:31:30 +00:00
text . id . set ( Some ( new_id ) ) ;
2022-11-16 00:05:22 +00:00
2022-11-29 21:31:04 +00:00
// Safety: we promise not to re-alias this text later on after committing it to the mutation
let value = unsafe { std ::mem ::transmute ( text . value ) } ;
2022-11-22 01:00:34 +00:00
// Add the mutation to the list
2022-11-23 03:59:56 +00:00
self . mutations . push ( HydrateText {
2022-11-22 01:00:34 +00:00
id : new_id ,
2022-12-20 01:28:44 +00:00
path : & template . template . get ( ) . node_paths [ idx ] [ 1 .. ] ,
2022-11-29 21:31:04 +00:00
value ,
2022-11-22 01:00:34 +00:00
} ) ;
2022-11-04 05:30:26 +00:00
2022-11-22 01:00:34 +00:00
// Since we're hydrating an existing node, we don't create any new nodes
0
}
2022-11-16 19:48:47 +00:00
2022-11-30 16:24:13 +00:00
pub ( crate ) fn create_placeholder (
2022-11-22 01:00:34 +00:00
& mut self ,
2022-12-13 02:31:30 +00:00
placeholder : & VPlaceholder ,
2022-11-23 03:59:56 +00:00
template : & ' b VNode < ' b > ,
2022-11-22 01:00:34 +00:00
idx : usize ,
) -> usize {
2022-11-30 16:24:13 +00:00
// Allocate a dynamic element reference for this text node
2022-12-20 01:28:44 +00:00
let id = self . next_element ( template , template . template . get ( ) . node_paths [ idx ] ) ;
2022-11-16 19:48:47 +00:00
2022-11-30 16:24:13 +00:00
// Make sure the text node is assigned to the correct element
2022-12-13 02:31:30 +00:00
placeholder . id . set ( Some ( id ) ) ;
2022-11-16 19:48:47 +00:00
2022-11-30 16:24:13 +00:00
// Assign the ID to the existing node in the template
self . mutations . push ( AssignId {
2022-12-20 01:28:44 +00:00
path : & template . template . get ( ) . node_paths [ idx ] [ 1 .. ] ,
2022-11-30 16:24:13 +00:00
id ,
} ) ;
2022-11-16 19:48:47 +00:00
2022-11-30 16:24:13 +00:00
// Since the placeholder is already in the DOM, we don't create any new nodes
0
}
2022-11-16 19:48:47 +00:00
2022-11-29 21:31:04 +00:00
pub ( super ) fn create_component_node (
2022-11-22 01:00:34 +00:00
& mut self ,
2022-11-23 03:59:56 +00:00
template : & ' b VNode < ' b > ,
component : & ' b VComponent < ' b > ,
2022-11-22 01:00:34 +00:00
idx : usize ,
) -> usize {
2022-12-24 00:33:15 +00:00
use RenderReturn ::* ;
2022-12-13 02:31:30 +00:00
2022-12-24 00:33:15 +00:00
// Load up a ScopeId for this vcomponent
let scope = self . load_scope_from_vcomponent ( component ) ;
2022-11-02 01:42:29 +00:00
2022-11-22 01:00:34 +00:00
component . scope . set ( Some ( scope ) ) ;
2022-11-04 00:34:42 +00:00
2022-12-24 00:33:15 +00:00
match unsafe { self . run_scope ( scope ) . extend_lifetime_ref ( ) } {
Ready ( t ) = > self . mount_component ( scope , template , t , idx ) ,
Aborted ( t ) = > self . mount_aborted ( template , t ) ,
2022-12-25 06:43:22 +00:00
Pending ( _ ) = > self . mount_async ( template , idx , scope ) ,
2022-10-28 04:58:47 +00:00
}
}
2022-11-22 01:00:34 +00:00
2022-12-24 00:33:15 +00:00
/// Load a scope from a vcomponent. If the props don't exist, that means the component is currently "live"
fn load_scope_from_vcomponent ( & mut self , component : & VComponent ) -> ScopeId {
component
. props
. take ( )
. map ( | props | {
let unbounded_props : Box < dyn AnyProps > = unsafe { std ::mem ::transmute ( props ) } ;
self . new_scope ( unbounded_props , component . name ) . id
} )
. unwrap_or_else ( | | component . scope . get ( ) . unwrap ( ) )
2022-10-28 04:58:47 +00:00
}
2022-11-22 01:00:34 +00:00
2022-11-24 07:15:01 +00:00
fn mount_component (
& mut self ,
scope : ScopeId ,
parent : & ' b VNode < ' b > ,
new : & ' b VNode < ' b > ,
idx : usize ,
) -> usize {
2022-11-22 18:05:13 +00:00
// Keep track of how many mutations are in the buffer in case we need to split them out if a suspense boundary
// is encountered
2022-12-01 05:46:15 +00:00
let mutations_to_this_point = self . mutations . edits . len ( ) ;
2022-11-22 01:00:34 +00:00
// Create the component's root element
2022-11-24 07:15:01 +00:00
let created = self . create_scope ( scope , new ) ;
2022-11-22 01:00:34 +00:00
2022-11-22 18:05:13 +00:00
// If there are no suspense leaves below us, then just don't bother checking anything suspense related
if self . collected_leaves . is_empty ( ) {
return created ;
2022-11-22 01:00:34 +00:00
}
2022-11-22 18:05:13 +00:00
// If running the scope has collected some leaves and *this* component is a boundary, then handle the suspense
2022-12-05 23:30:49 +00:00
let boundary = match self . scopes [ scope . 0 ] . has_context ::< Rc < SuspenseContext > > ( ) {
2022-12-05 22:16:54 +00:00
Some ( boundary ) = > boundary ,
2022-11-22 18:05:13 +00:00
_ = > return created ,
} ;
// Since this is a boundary, use its placeholder within the template as the placeholder for the suspense tree
2022-12-20 01:28:44 +00:00
let new_id = self . next_element ( new , parent . template . get ( ) . node_paths [ idx ] ) ;
2022-11-22 18:05:13 +00:00
// Now connect everything to the boundary
self . scopes [ scope . 0 ] . placeholder . set ( Some ( new_id ) ) ;
// This involves breaking off the mutations to this point, and then creating a new placeholder for the boundary
// Note that we break off dynamic mutations only - since static mutations aren't rendered immediately
let split_off = unsafe {
std ::mem ::transmute ::< Vec < Mutation > , Vec < Mutation > > (
2022-12-01 05:46:15 +00:00
self . mutations . edits . split_off ( mutations_to_this_point ) ,
2022-11-22 18:05:13 +00:00
)
} ;
2022-12-01 05:46:15 +00:00
boundary . mutations . borrow_mut ( ) . edits . extend ( split_off ) ;
2022-11-22 18:05:13 +00:00
boundary . created_on_stack . set ( created ) ;
boundary
. waiting_on
. borrow_mut ( )
. extend ( self . collected_leaves . drain ( .. ) ) ;
// Now assign the placeholder in the DOM
2022-11-23 03:59:56 +00:00
self . mutations . push ( AssignId {
2022-11-22 18:05:13 +00:00
id : new_id ,
2022-12-20 01:28:44 +00:00
path : & parent . template . get ( ) . node_paths [ idx ] [ 1 .. ] ,
2022-11-22 18:05:13 +00:00
} ) ;
0
2022-11-22 01:00:34 +00:00
}
2022-12-24 00:43:19 +00:00
fn mount_aborted ( & mut self , parent : & ' b VNode < ' b > , placeholder : & VPlaceholder ) -> usize {
let id = self . next_element ( parent , & [ ] ) ;
self . mutations . push ( Mutation ::CreatePlaceholder { id } ) ;
placeholder . id . set ( Some ( id ) ) ;
1
}
2022-11-22 01:00:34 +00:00
/// Take the rendered nodes from a component and handle them if they were async
///
/// IE simply assign an ID to the placeholder
2022-12-24 00:43:19 +00:00
fn mount_async ( & mut self , template : & VNode , idx : usize , scope : ScopeId ) -> usize {
2022-12-20 01:28:44 +00:00
let new_id = self . next_element ( template , template . template . get ( ) . node_paths [ idx ] ) ;
2022-11-22 01:00:34 +00:00
// Set the placeholder of the scope
self . scopes [ scope . 0 ] . placeholder . set ( Some ( new_id ) ) ;
// Since the placeholder is already in the DOM, we don't create any new nodes
2022-11-23 03:59:56 +00:00
self . mutations . push ( AssignId {
2022-11-22 01:00:34 +00:00
id : new_id ,
2022-12-20 01:28:44 +00:00
path : & template . template . get ( ) . node_paths [ idx ] [ 1 .. ] ,
2022-11-22 01:00:34 +00:00
} ) ;
0
}
2022-12-13 02:31:30 +00:00
fn set_slot (
& mut self ,
template : & ' b VNode < ' b > ,
slot : & ' b Cell < Option < ElementId > > ,
id : usize ,
) -> ElementId {
2022-12-20 01:28:44 +00:00
let id = self . next_element ( template , template . template . get ( ) . node_paths [ id ] ) ;
2022-12-13 02:31:30 +00:00
slot . set ( Some ( id ) ) ;
id
}
}
fn collect_dyn_node_range (
2022-12-22 17:36:38 +00:00
dynamic_nodes : & mut Peekable < impl Iterator < Item = ( ( usize , usize ) , & 'static [ u8 ] ) > > ,
root_idx : u8 ,
2022-12-13 02:31:30 +00:00
) -> Option < ( usize , usize ) > {
let start = match dynamic_nodes . peek ( ) {
2022-12-22 17:36:38 +00:00
Some ( ( ( _ , idx ) , [ first , .. ] ) ) if * first = = root_idx = > * idx ,
2022-12-13 02:31:30 +00:00
_ = > return None ,
} ;
let mut end = start ;
2022-12-22 17:36:38 +00:00
while let Some ( ( ( _ , idx ) , p ) ) =
dynamic_nodes . next_if ( | ( _ , p ) | matches! ( p , [ idx , .. ] if * idx = = root_idx ) )
{
2022-12-13 02:31:30 +00:00
if p . len ( ) = = 1 {
continue ;
}
end = idx ;
}
Some ( ( start , end ) )
2022-10-28 04:58:47 +00:00
}