diff --git a/__tests__/react-dom/ReactFunctionComponent-test.js b/__tests__/react-dom/ReactFunctionComponent-test.js index 055f36c..70ae515 100644 --- a/__tests__/react-dom/ReactFunctionComponent-test.js +++ b/__tests__/react-dom/ReactFunctionComponent-test.js @@ -17,6 +17,12 @@ function FunctionComponent(props) { return
{props.name}
; } +function sleep(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms) + }) +} + describe('ReactFunctionComponent', () => { beforeEach(() => { jest.resetModules(); @@ -25,10 +31,11 @@ describe('ReactFunctionComponent', () => { ReactTestUtils = require('../utils/test-utils') }); - it('should render stateless component', () => { + it('should render stateless component', async () => { const el = document.createElement('div'); // console.log(FunctionComponent.toString()) ReactDOM.createRoot(el).render(); + await sleep(10) expect(el.textContent).toBe('A'); }); diff --git a/examples/hello-world/src/main.tsx b/examples/hello-world/src/main.tsx index fd0b0ef..8f70611 100644 --- a/examples/hello-world/src/main.tsx +++ b/examples/hello-world/src/main.tsx @@ -1,5 +1,5 @@ import {createRoot} from 'react-dom' -import App from "./App.tsx"; +import App from './App.tsx' const root = createRoot(document.getElementById("root")) root.render() diff --git a/packages/react-dom/src/host_config.rs b/packages/react-dom/src/host_config.rs index 1e15926..f7e898b 100644 --- a/packages/react-dom/src/host_config.rs +++ b/packages/react-dom/src/host_config.rs @@ -1,8 +1,11 @@ use std::any::Any; +use std::cell::RefCell; use std::rc::Rc; +use js_sys::{Function, global, Promise}; use js_sys::JSON::stringify; use wasm_bindgen::JsValue; +use wasm_bindgen::prelude::*; use web_sys::{Node, window}; use react_reconciler::HostConfig; @@ -31,6 +34,20 @@ pub fn to_string(js_value: &JsValue) -> String { }) } +#[wasm_bindgen] +extern "C" { + type Global; + + #[wasm_bindgen] + fn queueMicrotask(closure: &JsValue); + + #[wasm_bindgen] + fn setTimeout(closure: &JsValue, timeout: i32); + + #[wasm_bindgen(method, getter, js_name = queueMicrotask)] + fn hasQueueMicrotask(this: &Global) -> JsValue; +} + impl HostConfig for ReactDomHostConfig { fn create_text_instance(&self, content: &JsValue) -> Rc { let window = window().expect("no global `window` exists"); @@ -135,4 +152,35 @@ impl HostConfig for ReactDomHostConfig { } } } + + fn schedule_microtask(&self, callback: Box) { + let closure = Rc::new(RefCell::new(Some(Closure::wrap(callback)))); + + if global() + .unchecked_into::() + .hasQueueMicrotask() + .is_function() + { + let closure_clone = closure.clone(); + queueMicrotask(&closure_clone.borrow_mut().as_ref().unwrap().as_ref().unchecked_ref::()); + closure_clone.borrow_mut().take().unwrap_throw().forget(); + } else if js_sys::Reflect::get(&*global(), &JsValue::from_str("Promise")) + .map(|value| value.is_function()) + .unwrap_or(false) + { + let promise = Promise::resolve(&JsValue::NULL); + let closure_clone = closure.clone(); + let c = Closure::wrap(Box::new(move |_v| { + let b = closure_clone.borrow_mut(); + let function = b.as_ref().unwrap().as_ref().unchecked_ref::(); + let _ = function.call0(&JsValue::NULL); + }) as Box); + let _ = promise.then(&c); + c.forget(); + } else { + let closure_clone = closure.clone(); + setTimeout(&closure_clone.borrow_mut().as_ref().unwrap().as_ref().unchecked_ref::(), 0); + closure_clone.borrow_mut().take().unwrap_throw().forget(); + } + } } diff --git a/packages/react-reconciler/src/begin_work.rs b/packages/react-reconciler/src/begin_work.rs index 6560b28..02863e3 100644 --- a/packages/react-reconciler/src/begin_work.rs +++ b/packages/react-reconciler/src/begin_work.rs @@ -8,16 +8,18 @@ use shared::derive_from_js_value; use crate::child_fiber::{mount_child_fibers, reconcile_child_fibers}; use crate::fiber::{FiberNode, MemoizedState}; use crate::fiber_hooks::render_with_hooks; +use crate::fiber_lanes::Lane; use crate::update_queue::process_update_queue; use crate::work_tags::WorkTag; pub fn begin_work( work_in_progress: Rc>, + render_lane: Lane, ) -> Result>>, JsValue> { let tag = work_in_progress.clone().borrow().tag.clone(); return match tag { - WorkTag::FunctionComponent => update_function_component(work_in_progress.clone()), - WorkTag::HostRoot => Ok(update_host_root(work_in_progress.clone())), + WorkTag::FunctionComponent => update_function_component(work_in_progress.clone(), render_lane), + WorkTag::HostRoot => Ok(update_host_root(work_in_progress.clone(), render_lane)), WorkTag::HostComponent => Ok(update_host_component(work_in_progress.clone())), WorkTag::HostText => Ok(None), }; @@ -25,13 +27,14 @@ pub fn begin_work( fn update_function_component( work_in_progress: Rc>, + render_lane: Lane, ) -> Result>>, JsValue> { - let next_children = render_with_hooks(work_in_progress.clone())?; + let next_children = render_with_hooks(work_in_progress.clone(), render_lane)?; reconcile_children(work_in_progress.clone(), Some(next_children)); Ok(work_in_progress.clone().borrow().child.clone()) } -fn update_host_root(work_in_progress: Rc>) -> Option>> { +fn update_host_root(work_in_progress: Rc>, render_lane: Lane) -> Option>> { let work_in_progress_cloned = work_in_progress.clone(); let base_state; @@ -44,7 +47,7 @@ fn update_host_root(work_in_progress: Rc>) -> Option, pub current: Rc>, pub finished_work: Option>>, + pub pending_lanes: Lane, + pub finished_lane: Lane, } impl FiberRootNode { @@ -235,8 +240,18 @@ impl FiberRootNode { container, current: host_root_fiber, finished_work: None, + pending_lanes: Lane::NoLane, + finished_lane: Lane::NoLane, } } + + pub fn mark_root_finished(&mut self, lane: Lane) { + self.pending_lanes &= !lane; + } + + pub fn mark_root_updated(&mut self, lane: Lane) { + self.pending_lanes = merge_lanes(self.pending_lanes.clone(), lane) + } } struct QueueItem { @@ -263,7 +278,7 @@ impl Debug for FiberRootNode { while let Some(QueueItem { node: current, depth }) = queue.pop_front() { let current_ref = current.borrow(); - write!(f, "{:?}", current_ref); + write!(f, "{:?}", current_ref).expect("TODO: panic print FiberNode"); if let Some(ref child) = current_ref.child { queue.push_back(QueueItem::new(Rc::clone(child), depth + 1)); diff --git a/packages/react-reconciler/src/fiber_hooks.rs b/packages/react-reconciler/src/fiber_hooks.rs index 2929b24..3a59cea 100644 --- a/packages/react-reconciler/src/fiber_hooks.rs +++ b/packages/react-reconciler/src/fiber_hooks.rs @@ -8,10 +8,11 @@ use web_sys::js_sys::{Function, Object, Reflect}; use shared::log; use crate::fiber::{FiberNode, MemoizedState}; +use crate::fiber_lanes::{Lane, request_update_lane}; use crate::update_queue::{ create_update, create_update_queue, enqueue_update, process_update_queue, UpdateQueue, }; -use crate::work_loop::WorkLoop; +use crate::work_loop::schedule_update_on_fiber; #[wasm_bindgen] extern "C" { @@ -21,7 +22,7 @@ extern "C" { static mut CURRENTLY_RENDERING_FIBER: Option>> = None; static mut WORK_IN_PROGRESS_HOOK: Option>> = None; static mut CURRENT_HOOK: Option>> = None; -pub static mut WORK_LOOP: Option>> = None; +static mut RENDER_LANE: Lane = Lane::NoLane; #[derive(Debug, Clone)] pub struct Hook { @@ -56,9 +57,10 @@ fn update_hooks_to_dispatcher(is_update: bool) { updateDispatcher(&object.into()); } -pub fn render_with_hooks(work_in_progress: Rc>) -> Result { +pub fn render_with_hooks(work_in_progress: Rc>, lane: Lane) -> Result { unsafe { CURRENTLY_RENDERING_FIBER = Some(work_in_progress.clone()); + RENDER_LANE = lane; } let work_in_progress_cloned = work_in_progress.clone(); @@ -89,6 +91,7 @@ pub fn render_with_hooks(work_in_progress: Rc>) -> Result Result, JsValue> { base_state, queue.clone(), CURRENTLY_RENDERING_FIBER.clone().unwrap(), + RENDER_LANE.clone(), ); } log!("memoized_state {:?}", hook_cloned.borrow().memoized_state); @@ -281,14 +285,10 @@ fn dispatch_set_state( update_queue: Rc>, action: &JsValue, ) { - let update = create_update(action.clone()); + let lane = request_update_lane(); + let update = create_update(action.clone(), lane.clone()); enqueue_update(update_queue.clone(), update); unsafe { - WORK_LOOP - .as_ref() - .unwrap() - .clone() - .borrow() - .schedule_update_on_fiber(fiber.clone()); + schedule_update_on_fiber(fiber.clone(), lane); } } diff --git a/packages/react-reconciler/src/fiber_lanes.rs b/packages/react-reconciler/src/fiber_lanes.rs new file mode 100644 index 0000000..a8216c7 --- /dev/null +++ b/packages/react-reconciler/src/fiber_lanes.rs @@ -0,0 +1,25 @@ +use bitflags::bitflags; + +bitflags! { + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Lane: u8 { + const NoLane = 0b0000000000000000000000000000000; + const SyncLane = 0b0000000000000000000000000000001; + // const AsyncLane = 0b0000000000000000000000000000010; + } +} + +pub fn get_highest_priority(lanes: Lane) -> Lane { + let lanes = lanes.bits(); + let highest_priority = lanes & (lanes.wrapping_neg()); + Lane::from_bits_truncate(highest_priority) +} + +pub fn merge_lanes(lane_a: Lane, lane_b: Lane) -> Lane { + lane_a | lane_b +} + +pub fn request_update_lane() -> Lane { + Lane::SyncLane +} + diff --git a/packages/react-reconciler/src/lib.rs b/packages/react-reconciler/src/lib.rs index 3a7cb69..51e159b 100644 --- a/packages/react-reconciler/src/lib.rs +++ b/packages/react-reconciler/src/lib.rs @@ -4,10 +4,12 @@ use std::rc::Rc; use wasm_bindgen::JsValue; +use crate::complete_work::CompleteWork; use crate::fiber::{FiberNode, FiberRootNode, StateNode}; -use crate::fiber_hooks::WORK_LOOP; +// use crate::fiber_hooks::{WORK_LOOP as Fiber_HOOKS}; +use crate::fiber_lanes::Lane; use crate::update_queue::{create_update, create_update_queue, enqueue_update}; -use crate::work_loop::WorkLoop; +use crate::work_loop::schedule_update_on_fiber; use crate::work_tags::WorkTag; mod begin_work; @@ -20,6 +22,11 @@ mod fiber_hooks; mod update_queue; mod work_loop; mod work_tags; +mod fiber_lanes; +mod sync_task_queue; + +pub static mut HOST_CONFIG: Option> = None; +static mut COMPLETE_WORK: Option = None; pub trait HostConfig { fn create_text_instance(&self, content: &JsValue) -> Rc; @@ -28,17 +35,17 @@ pub trait HostConfig { fn append_child_to_container(&self, child: Rc, parent: Rc); fn remove_child(&self, child: Rc, container: Rc); fn commit_text_update(&self, text_instance: Rc, content: String); - fn insert_child_to_container( &self, child: Rc, container: Rc, before: Rc, ); + fn schedule_microtask(&self, callback: Box); } pub struct Reconciler { - host_config: Rc, + pub host_config: Rc, } impl Reconciler { @@ -63,19 +70,17 @@ impl Reconciler { pub fn update_container(&self, element: JsValue, root: Rc>) -> JsValue { let host_root_fiber = Rc::clone(&root).borrow().current.clone(); - let update = create_update(element.clone()); + let root_render_priority = Lane::SyncLane; + let update = create_update(element.clone(), root_render_priority.clone()); enqueue_update( host_root_fiber.borrow().update_queue.clone().unwrap(), update, ); - let work_loop = Rc::new(RefCell::new(WorkLoop::new(self.host_config.clone()))); unsafe { - WORK_LOOP = Some(work_loop.clone()); + HOST_CONFIG = Some(self.host_config.clone()); + COMPLETE_WORK = Some(CompleteWork::new(self.host_config.clone())); + schedule_update_on_fiber(host_root_fiber, root_render_priority); } - work_loop - .clone() - .borrow() - .schedule_update_on_fiber(host_root_fiber); element.clone() } } diff --git a/packages/react-reconciler/src/main.rs b/packages/react-reconciler/src/main.rs new file mode 100644 index 0000000..9270a6c --- /dev/null +++ b/packages/react-reconciler/src/main.rs @@ -0,0 +1,9 @@ +use crate::fiber_lanes::Lane; + +mod fiber_lanes; + +fn main() { + let mut a = Lane::NoLane | Lane::SyncLane; + println!("{:?}", a); + println!("{:?}", a == !Lane::NoLane) +} \ No newline at end of file diff --git a/packages/react-reconciler/src/sync_task_queue.rs b/packages/react-reconciler/src/sync_task_queue.rs new file mode 100644 index 0000000..c82fdee --- /dev/null +++ b/packages/react-reconciler/src/sync_task_queue.rs @@ -0,0 +1,19 @@ +static mut SYNC_QUEUE: Vec> = vec![]; +static mut IS_FLUSHING_SYNC_QUEUE: bool = false; + +pub fn schedule_sync_callback(callback: Box) { + unsafe { SYNC_QUEUE.push(callback) } +} + +pub fn flush_sync_callbacks() { + unsafe { + if !IS_FLUSHING_SYNC_QUEUE && !SYNC_QUEUE.is_empty() { + IS_FLUSHING_SYNC_QUEUE = true; + for callback in SYNC_QUEUE.iter_mut() { + callback(); + } + SYNC_QUEUE = vec![]; + IS_FLUSHING_SYNC_QUEUE = false; + } + } +} diff --git a/packages/react-reconciler/src/update_queue.rs b/packages/react-reconciler/src/update_queue.rs index e80a856..9b03528 100644 --- a/packages/react-reconciler/src/update_queue.rs +++ b/packages/react-reconciler/src/update_queue.rs @@ -7,6 +7,7 @@ use web_sys::js_sys::Function; use shared::log; use crate::fiber::{FiberNode, MemoizedState}; +use crate::fiber_lanes::Lane; #[derive(Clone, Debug)] pub struct UpdateAction; @@ -14,11 +15,13 @@ pub struct UpdateAction; #[derive(Clone, Debug)] pub struct Update { pub action: Option, + pub lane: Lane, + pub next: Option>>, } #[derive(Clone, Debug)] pub struct UpdateType { - pub pending: Option, + pub pending: Option>>, } #[derive(Clone, Debug)] @@ -27,14 +30,26 @@ pub struct UpdateQueue { pub dispatch: Option, } -pub fn create_update(action: JsValue) -> Update { +pub fn create_update(action: JsValue, lane: Lane) -> Update { Update { action: Some(action), + lane, + next: None, } } -pub fn enqueue_update(update_queue: Rc>, update: Update) { - update_queue.borrow_mut().shared.pending = Option::from(update); +pub fn enqueue_update(update_queue: Rc>, mut update: Update) { + let pending = update_queue.borrow().shared.pending.clone(); + let update_rc = Rc::new(RefCell::new(update)); + let update_option = Option::from(update_rc.clone()); + if pending.is_none() { + update_rc.borrow_mut().next = update_option.clone(); + } else { + let pending = pending.clone().unwrap(); + update_rc.borrow_mut().next = { pending.borrow().next.clone() }; + pending.borrow_mut().next = update_option.clone(); + } + update_queue.borrow_mut().shared.pending = update_option.clone(); } pub fn create_update_queue() -> Rc> { @@ -48,33 +63,46 @@ pub fn process_update_queue( mut base_state: Option, update_queue: Option>>, fiber: Rc>, + render_lane: Lane, ) -> Option { if update_queue.is_some() { let update_queue = update_queue.clone().unwrap().clone(); let pending = update_queue.borrow().shared.pending.clone(); update_queue.borrow_mut().shared.pending = None; if pending.is_some() { - let action = pending.unwrap().action; - match action { - None => {} - Some(action) => { - let f = action.dyn_ref::(); - base_state = match f { - None => Some(MemoizedState::MemoizedJsValue(action.clone())), - Some(f) => { - if let MemoizedState::MemoizedJsValue(base_state) = - base_state.as_ref().unwrap() - { - Some(MemoizedState::MemoizedJsValue( - f.call1(&JsValue::null(), base_state).unwrap(), - )) - } else { - log!("process_update_queue, base_state is not JsValue"); - None + let pending_update = pending.clone().unwrap(); + let mut update = pending_update.clone(); + loop { + let update_lane = update.borrow().lane.clone(); + if render_lane == update_lane { + let action = update.borrow().action.clone(); + match action { + None => {} + Some(action) => { + let f = action.dyn_ref::(); + base_state = match f { + None => Some(MemoizedState::MemoizedJsValue(action.clone())), + Some(f) => { + if let MemoizedState::MemoizedJsValue(base_state) = + base_state.as_ref().unwrap() + { + Some(MemoizedState::MemoizedJsValue( + f.call1(&JsValue::null(), base_state).unwrap(), + )) + } else { + log!("process_update_queue, base_state is not JsValue"); + None + } + } } } } } + let next = update.clone().borrow().next.clone(); + if next.is_none() || Rc::ptr_eq(&next.clone().unwrap(), &pending_update.clone()) { + break; + } + update = next.unwrap(); } } } else { diff --git a/packages/react-reconciler/src/work_loop.rs b/packages/react-reconciler/src/work_loop.rs index 050a6ea..abca79d 100644 --- a/packages/react-reconciler/src/work_loop.rs +++ b/packages/react-reconciler/src/work_loop.rs @@ -3,202 +3,221 @@ use std::rc::Rc; use wasm_bindgen::JsValue; -use shared::log; +use shared::{is_dev, log}; +use crate::{COMPLETE_WORK, HOST_CONFIG, HostConfig}; use crate::begin_work::begin_work; use crate::commit_work::CommitWork; -use crate::complete_work::CompleteWork; use crate::fiber::{FiberNode, FiberRootNode, StateNode}; use crate::fiber_flags::get_mutation_mask; -use crate::HostConfig; +use crate::fiber_lanes::{get_highest_priority, Lane, merge_lanes}; +use crate::sync_task_queue::{flush_sync_callbacks, schedule_sync_callback}; use crate::work_tags::WorkTag; static mut WORK_IN_PROGRESS: Option>> = None; +static mut WORK_IN_PROGRESS_ROOT_RENDER_LANE: Lane = Lane::NoLane; -pub struct WorkLoop { - // make the first param to be &self not &mut self - // work_in_progress: Option>>, - complete_work: CompleteWork, +pub fn schedule_update_on_fiber(fiber: Rc>, lane: Lane) { + if is_dev() { + log!("schedule_update_on_fiber, {:?} {:?}", fiber, lane); + } + + let root = mark_update_lane_from_fiber_to_root(fiber, lane.clone()); + if root.is_none() { + return; + } + root.as_ref().unwrap().borrow_mut().mark_root_updated(lane); + ensure_root_is_scheduled(root.unwrap()) } -impl WorkLoop { - pub fn new(host_config: Rc) -> Self { - Self { - // work_in_progress: None, - complete_work: CompleteWork::new(host_config), - } +pub fn mark_update_lane_from_fiber_to_root( + fiber: Rc>, + lane: Lane, +) -> Option>> { + let mut node = Rc::clone(&fiber); + let mut parent = Rc::clone(&fiber).borrow()._return.clone(); + + let node_lanes = { node.borrow().lanes.clone() }; + node.borrow_mut().lanes = merge_lanes(node_lanes, lane.clone()); + let alternate = node.borrow().alternate.clone(); + if alternate.is_some() { + let alternate = alternate.unwrap(); + let alternate_lanes = { alternate.borrow().lanes.clone() }; + alternate.borrow_mut().lanes = merge_lanes(alternate_lanes, lane); } - pub fn schedule_update_on_fiber(&self, fiber: Rc>) { - let root = self.mark_update_lane_from_fiber_to_root(fiber); - if root.is_none() { - return; - } - self.ensure_root_is_scheduled(root.unwrap()) - } - - pub fn mark_update_lane_from_fiber_to_root( - &self, - fiber: Rc>, - ) -> Option>> { - let mut node = Rc::clone(&fiber); - let mut parent = Rc::clone(&fiber).borrow()._return.clone(); - - while parent.is_some() { - node = parent.clone().unwrap(); - let rc = Rc::clone(&parent.unwrap()); - let rc_ref = rc.borrow(); - let next = match rc_ref._return.as_ref() { - None => None, - Some(node) => { - let a = node.clone(); - Some(a) - } - }; - parent = next; - } + while parent.is_some() { + node = parent.clone().unwrap(); + let rc = Rc::clone(&parent.unwrap()); + let rc_ref = rc.borrow(); + let next = match rc_ref._return.as_ref() { + None => None, + Some(node) => { + let a = node.clone(); + Some(a) + } + }; + parent = next; + } - let fiber_node_rc = Rc::clone(&node); - let fiber_node = fiber_node_rc.borrow(); - if fiber_node.tag == WorkTag::HostRoot { - if let Some(state_node) = fiber_node.state_node.clone() { - if let StateNode::FiberRootNode(fiber_root_node) = &*(state_node.clone()) { - return Some(Rc::clone(fiber_root_node)); - } + let fiber_node_rc = Rc::clone(&node); + let fiber_node = fiber_node_rc.borrow(); + if fiber_node.tag == WorkTag::HostRoot { + if let Some(state_node) = fiber_node.state_node.clone() { + if let StateNode::FiberRootNode(fiber_root_node) = &*(state_node.clone()) { + return Some(Rc::clone(fiber_root_node)); } } + } - None + None +} + +fn ensure_root_is_scheduled(root: Rc>) { + let root_cloned = root.clone(); + let update_lane = get_highest_priority(root.borrow().pending_lanes.clone()); + if update_lane == Lane::NoLane { + return; + } + if update_lane == Lane::SyncLane { + if is_dev() { + log!("Schedule in microtask, priority {:?}", update_lane); + } + } + schedule_sync_callback(Box::new(move || { + perform_sync_work_on_root(root_cloned.clone(), update_lane.clone()); + })); + unsafe { + HOST_CONFIG.as_ref().unwrap() + .schedule_microtask(Box::new(|| flush_sync_callbacks())); } +} - fn ensure_root_is_scheduled(&self, root: Rc>) { - self.perform_sync_work_on_root(root); +fn perform_sync_work_on_root(root: Rc>, lane: Lane) { + let next_lane = get_highest_priority(root.borrow().pending_lanes.clone()); + log!("perform_sync_work_on_root {:?}", next_lane); + if next_lane != Lane::SyncLane { + ensure_root_is_scheduled(root.clone()); + return; } - fn perform_sync_work_on_root(&self, root: Rc>) { - self.prepare_fresh_stack(Rc::clone(&root)); + prepare_fresh_stack(root.clone(), lane.clone()); - loop { - match self.work_loop() { - Ok(_) => { - break; - } - Err(e) => unsafe { - log!("work_loop error {:?}", e); - WORK_IN_PROGRESS = None - }, - }; - } + loop { + match work_loop() { + Ok(_) => { + break; + } + Err(e) => unsafe { + log!("work_loop error {:?}", e); + WORK_IN_PROGRESS = None + }, + }; + } - log!("{:?}", *root.clone().borrow()); + log!("{:?}", *root.clone().borrow()); + + unsafe { WORK_IN_PROGRESS_ROOT_RENDER_LANE = Lane::NoLane; } + let finished_work = { + root.clone() + .borrow() + .current + .clone() + .borrow() + .alternate + .clone() + }; + root.clone().borrow_mut().finished_work = finished_work; + root.clone().borrow_mut().finished_lane = lane; + + commit_root(root); +} - let finished_work = { - root.clone() - .borrow() - .current - .clone() - .borrow() - .alternate - .clone() - }; +fn commit_root(root: Rc>) { + let cloned = root.clone(); + if cloned.borrow().finished_work.is_none() { + return; + } + let lane = root.borrow().finished_lane.clone(); + + let finished_work = cloned.borrow().finished_work.clone().unwrap(); + cloned.borrow_mut().finished_work = None; + cloned.borrow_mut().finished_lane = Lane::NoLane; + + cloned.borrow_mut().mark_root_finished(lane.clone()); - root.clone().borrow_mut().finished_work = finished_work; - self.commit_root(root); + if lane == Lane::NoLane { + log!("Commit phase finished lane should not be NoLane") } - fn commit_root(&self, root: Rc>) { - let cloned = root.clone(); - if cloned.borrow().finished_work.is_none() { - return; - } - let finished_work = cloned.borrow().finished_work.clone().unwrap(); - cloned.borrow_mut().finished_work = None; - - let subtree_has_effect = - get_mutation_mask().contains(finished_work.clone().borrow().subtree_flags.clone()); - let root_has_effect = - get_mutation_mask().contains(finished_work.clone().borrow().flags.clone()); - - let commit_work = &mut CommitWork::new(self.complete_work.host_config.clone()); - if subtree_has_effect || root_has_effect { - commit_work.commit_mutation_effects(finished_work.clone()); - cloned.borrow_mut().current = finished_work.clone(); - } else { - cloned.borrow_mut().current = finished_work.clone(); - } + let subtree_has_effect = + get_mutation_mask().contains(finished_work.clone().borrow().subtree_flags.clone()); + let root_has_effect = + get_mutation_mask().contains(finished_work.clone().borrow().flags.clone()); + + let commit_work = &mut CommitWork::new(unsafe { HOST_CONFIG.clone().unwrap() }); + if subtree_has_effect || root_has_effect { + commit_work.commit_mutation_effects(finished_work.clone()); + cloned.borrow_mut().current = finished_work.clone(); + } else { + cloned.borrow_mut().current = finished_work.clone(); } +} - fn prepare_fresh_stack(&self, root: Rc>) { - let root = Rc::clone(&root); - // self.work_in_progress = Some(FiberNode::create_work_in_progress( - // root.borrow().current.clone(), - // Rc::new(JsValue::null()), - // )); - unsafe { - WORK_IN_PROGRESS = Some(FiberNode::create_work_in_progress( - root.borrow().current.clone(), - JsValue::null(), - )); - log!( - "prepare_fresh_stack {:?} {:?}", - WORK_IN_PROGRESS.clone().unwrap().clone().borrow()._type, - WORK_IN_PROGRESS - .clone() - .unwrap() - .clone() - .borrow() - .memoized_state - ); - } +fn prepare_fresh_stack(root: Rc>, lane: Lane) { + let root = root.clone(); + unsafe { + WORK_IN_PROGRESS = Some(FiberNode::create_work_in_progress( + root.borrow().current.clone(), + JsValue::null(), + )); + WORK_IN_PROGRESS_ROOT_RENDER_LANE = lane; } +} - fn work_loop(&self) -> Result<(), JsValue> { - // while self.work_in_progress.is_some() { - // self.perform_unit_of_work(self.work_in_progress.clone().unwrap())?; - // } - unsafe { - while WORK_IN_PROGRESS.is_some() { - self.perform_unit_of_work(WORK_IN_PROGRESS.clone().unwrap())?; - } - } - Ok(()) - } - - fn perform_unit_of_work(&self, fiber: Rc>) -> Result<(), JsValue> { - let next = begin_work(fiber.clone())?; - let pending_props = { fiber.clone().borrow().pending_props.clone() }; - fiber.clone().borrow_mut().memoized_props = pending_props; - if next.is_none() { - self.complete_unit_of_work(fiber.clone()); - } else { - // self.work_in_progress = Some(next.unwrap()); - unsafe { WORK_IN_PROGRESS = Some(next.unwrap()) } +fn work_loop() -> Result<(), JsValue> { + // while self.work_in_progress.is_some() { + // self.perform_unit_of_work(self.work_in_progress.clone().unwrap())?; + // } + unsafe { + while WORK_IN_PROGRESS.is_some() { + perform_unit_of_work(WORK_IN_PROGRESS.clone().unwrap())?; } - Ok(()) } + Ok(()) +} + +fn perform_unit_of_work(fiber: Rc>) -> Result<(), JsValue> { + let next = begin_work(fiber.clone(), unsafe { WORK_IN_PROGRESS_ROOT_RENDER_LANE.clone() })?; + let pending_props = { fiber.clone().borrow().pending_props.clone() }; + fiber.clone().borrow_mut().memoized_props = pending_props; + if next.is_none() { + complete_unit_of_work(fiber.clone()); + } else { + // self.work_in_progress = Some(next.unwrap()); + unsafe { WORK_IN_PROGRESS = Some(next.unwrap()) } + } + Ok(()) +} - fn complete_unit_of_work(&self, fiber: Rc>) { - let mut node: Option>> = Some(fiber); +fn complete_unit_of_work(fiber: Rc>) { + let mut node: Option>> = Some(fiber); + unsafe { loop { - let next = self - .complete_work - .complete_work(node.clone().unwrap().clone()); + let next = COMPLETE_WORK + .as_ref().unwrap().complete_work(node.clone().unwrap().clone()); if next.is_some() { // self.work_in_progress = next.clone(); - unsafe { - WORK_IN_PROGRESS = next.clone(); - } + WORK_IN_PROGRESS = next.clone(); return; } let sibling = node.clone().unwrap().clone().borrow().sibling.clone(); if sibling.is_some() { // self.work_in_progress = next.clone(); - unsafe { - WORK_IN_PROGRESS = sibling.clone(); - } + WORK_IN_PROGRESS = sibling.clone(); return; } @@ -207,17 +226,14 @@ impl WorkLoop { if _return.is_none() { // node = None; // self.work_in_progress = None; - unsafe { - WORK_IN_PROGRESS = None; - } + WORK_IN_PROGRESS = None; break; } else { node = _return; // self.work_in_progress = node.clone(); - unsafe { - WORK_IN_PROGRESS = node.clone(); - } + WORK_IN_PROGRESS = node.clone(); } } } } +// } diff --git a/packages/shared/src/lib.rs b/packages/shared/src/lib.rs index 190de33..77fe2d4 100644 --- a/packages/shared/src/lib.rs +++ b/packages/shared/src/lib.rs @@ -21,7 +21,8 @@ pub fn derive_from_js_value(js_value: &JsValue, str: &str) -> JsValue { } pub fn is_dev() -> bool { - env!("ENV") == "dev" + // env!("ENV") == "dev" + true } pub fn type_of(val: &JsValue, _type: &str) -> bool {