Skip to content

Commit

Permalink
Support multi-threaded access for nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
codenikel committed Dec 22, 2023
1 parent 8f81e10 commit 9231778
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 130 deletions.
14 changes: 8 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/collaboration/src/collaborator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<'a, N: 'static + RadiantNode + serde::de::DeserializeOwned> Collaborator<N>
EntryChange::Removed(_val) => {}
EntryChange::Updated(_old, new) => {
let id = Uuid::parse_str(key).unwrap();
if let Some(node) = document.get_node_mut(id) {
if let Some(mut node) = document.get_node_mut(id) {
let n: String = new.clone().cast().unwrap();
node.replace(&n);
}
Expand Down Expand Up @@ -120,7 +120,7 @@ impl<N: RadiantNode> RadiantDocumentListener<N> for Collaborator<N> {
let Some(awareness) = awareness.try_write() else {
return;
};
if let Some(node) = document.get_node(id) {
if let Some(node) = document.node(id) {
let doc = awareness.doc();
let Ok(mut txn) = doc.try_transact_mut() else {
log::error!("Failed to transact");
Expand Down
2 changes: 1 addition & 1 deletion crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ futures-intrusive = "0.5"
macro_magic = "0.5.0"
radiantkit-macros = { version = "0.0.1", path = "../macros" }
once_cell = "1.19.0"
parking_lot = "0.12.1"
parking_lot = { version = "0.12.1", features = ["serde"] }
serde_json = "1.0.108"

[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand Down
21 changes: 15 additions & 6 deletions crates/core/src/document.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{collections::BTreeMap, cell::RefCell, rc::Rc};

use std::{collections::BTreeMap, cell::RefCell, rc::Rc, sync::Arc};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use crate::{
RadiantGroupNode, RadiantNode, RadiantSelectable, RadiantTessellatable, ScreenDescriptor,
SelectionComponent, SubscriptionId,
Expand Down Expand Up @@ -101,15 +101,15 @@ impl<N: RadiantNode> RadiantDocumentNode<N> {
}
self.artboards.iter_mut().for_each(|artboard| {
if let Some(prev_selected_node_id) = self.selected_node_id {
if let Some(node) = artboard.1.get_node_mut(prev_selected_node_id) {
if let Some(mut node) = artboard.1.get_node_mut(prev_selected_node_id) {
if let Some(component) = node.get_component_mut::<SelectionComponent>() {
component.set_selected(false);
node.set_needs_tessellation(true);
}
}
}
if let Some(id) = id {
if let Some(node) = artboard.1.get_node_mut(id) {
if let Some(mut node) = artboard.1.get_node_mut(id) {
if let Some(component) = node.get_component_mut::<SelectionComponent>() {
component.set_selected(true);
node.set_needs_tessellation(true);
Expand All @@ -120,7 +120,16 @@ impl<N: RadiantNode> RadiantDocumentNode<N> {
self.selected_node_id = id
}

pub fn get_node(&self, id: Uuid) -> Option<&N> {
pub fn node(&self, id: Uuid) -> Option<&Arc<RwLock<N>>> {
for artboard in &self.artboards {
if let Some(node) = artboard.1.node(id) {
return Some(node);
}
}
None
}

pub fn get_node(&self, id: Uuid) -> Option<RwLockReadGuard<N>> {
for artboard in &self.artboards {
if let Some(node) = artboard.1.get_node(id) {
return Some(node);
Expand All @@ -129,7 +138,7 @@ impl<N: RadiantNode> RadiantDocumentNode<N> {
None
}

pub fn get_node_mut(&mut self, id: Uuid) -> Option<&mut N> {
pub fn get_node_mut(&mut self, id: Uuid) -> Option<RwLockWriteGuard<N>> {
for artboard in &mut self.artboards {
if let Some(node) = artboard.1.get_node_mut(id) {
return Some(node);
Expand Down
5 changes: 3 additions & 2 deletions crates/core/src/interactions/bounding_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
};
use epaint::ClippedPrimitive;
use once_cell::sync::Lazy;
use parking_lot::RwLockWriteGuard;
use uuid::Uuid;

static BOUNDING_BOX_TOP_ID: Lazy<Uuid> = Lazy::new(|| Uuid::new_v4());
Expand Down Expand Up @@ -72,7 +73,7 @@ impl BoundingBoxInteraction {
|| id == *BOUNDING_BOX_TOP_LEFT_ID;
}

pub fn enable(&mut self, node: &impl RadiantNode, _screen_descriptor: &ScreenDescriptor) {
pub fn enable(&mut self, node: RwLockWriteGuard<impl RadiantNode>, _screen_descriptor: &ScreenDescriptor) {
if let Some(_component) = node.get_component::<TransformComponent>() {
let rect = node.get_bounding_rect();

Expand Down Expand Up @@ -116,7 +117,7 @@ impl BoundingBoxInteraction {
self.active_node_id = None;
}

pub fn update(&mut self, node: &impl RadiantNode, screen_descriptor: &ScreenDescriptor) {
pub fn update(&mut self, node: RwLockWriteGuard<impl RadiantNode>, screen_descriptor: &ScreenDescriptor) {
self.enable(node, screen_descriptor);
}
}
Expand Down
5 changes: 3 additions & 2 deletions crates/core/src/interactions/interaction_manager.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{BoundingBoxInteraction, RadiantNode, RadiantSceneMessage, ScreenDescriptor};
use epaint::ClippedPrimitive;
use parking_lot::RwLockWriteGuard;
use uuid::Uuid;

pub struct RadiantInteractionManager<M> {
Expand All @@ -21,7 +22,7 @@ impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>> RadiantInterac

pub fn enable_interactions(
&mut self,
node: &impl RadiantNode,
node: RwLockWriteGuard<impl RadiantNode>,
screen_descriptor: &ScreenDescriptor,
) {
self.bounding_box_interaction
Expand All @@ -34,7 +35,7 @@ impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>> RadiantInterac

pub fn update_interactions(
&mut self,
node: &impl RadiantNode,
node: RwLockWriteGuard<impl RadiantNode>,
screen_descriptor: &ScreenDescriptor,
) {
self.bounding_box_interaction
Expand Down
27 changes: 16 additions & 11 deletions crates/core/src/nodes/group.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use crate::{BaseNode, RadiantNode, RadiantTessellatable, ScreenDescriptor};
use epaint::ClippedPrimitive;
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::{collections::BTreeMap, sync::Arc};
use uuid::Uuid;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RadiantGroupNode<N: RadiantNode> {
pub base: BaseNode,
pub nodes: BTreeMap<Uuid, N>,
pub nodes: BTreeMap<Uuid, Arc<RwLock<N>>>,
}

impl<N: RadiantNode> RadiantGroupNode<N> {
Expand All @@ -20,32 +21,36 @@ impl<N: RadiantNode> RadiantGroupNode<N> {
}

pub fn add(&mut self, node: N) {
self.nodes.insert(node.get_id(), node);
self.nodes.insert(node.get_id(), Arc::new(RwLock::new(node)));
}

pub fn get_node(&self, id: Uuid) -> Option<&N> {
pub fn node(&self, id: Uuid) -> Option<&Arc<RwLock<N>>> {
self.nodes.get(&id)
}

pub fn get_node_mut(&mut self, id: Uuid) -> Option<&mut N> {
self.nodes.get_mut(&id)
pub fn get_node(&self, id: Uuid) -> Option<RwLockReadGuard<N>> {
self.nodes.get(&id).map(|n| n.read())
}

pub fn get_node_mut(&mut self, id: Uuid) -> Option<RwLockWriteGuard<N>> {
self.nodes.get_mut(&id).map(|n| n.write())
}

pub fn replace_node(&mut self, id: Uuid, node: N) {
self.nodes.insert(id, node);
self.nodes.insert(id, Arc::new(RwLock::new(node)));
}
}

impl<N: RadiantNode> RadiantTessellatable for RadiantGroupNode<N> {
fn attach(&mut self, screen_descriptor: &ScreenDescriptor) {
for node in &mut self.nodes.values_mut() {
node.attach(screen_descriptor);
node.write().attach(screen_descriptor);
}
}

fn detach(&mut self) {
for node in &mut self.nodes.values_mut() {
node.detach();
node.write().detach();
}
}

Expand All @@ -59,7 +64,7 @@ impl<N: RadiantNode> RadiantTessellatable for RadiantGroupNode<N> {
) -> Vec<ClippedPrimitive> {
let mut primitives = Vec::new();
for node in &mut self.nodes.values_mut() {
primitives.append(&mut node.tessellate(selection, screen_descriptor, fonts_manager));
primitives.append(&mut node.write().tessellate(selection, screen_descriptor, fonts_manager));
}
primitives
}
Expand All @@ -76,7 +81,7 @@ impl<N: RadiantNode> RadiantNode for RadiantGroupNode<N> {

fn handle_key_down(&mut self, key: crate::KeyCode) -> bool {
for node in &mut self.nodes.values_mut() {
if node.handle_key_down(key.clone()) {
if node.write().handle_key_down(key.clone()) {
return true;
}
}
Expand Down
15 changes: 8 additions & 7 deletions crates/core/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,12 @@ impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>, N: RadiantNode
self.document_mut().select(id);
if let Some(id) = id {
if !self.interaction_manager.is_interaction(id) {
if let Some(node) = self.document.write().get_node_mut(id) {
if let Some(mut node) = self.document.write().get_node_mut(id) {
node.tessellate(false, &self.screen_descriptor, &self.fonts_manager);
let response = RadiantSceneResponse::Selected { node: node.clone() };
self.interaction_manager
.enable_interactions(node, &self.screen_descriptor);
return Some(RadiantSceneResponse::Selected { node: node.clone() });
return Some(response);
} else {
self.interaction_manager.disable_interactions();
}
Expand All @@ -155,7 +156,7 @@ impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>, N: RadiantNode
{
return Some(RadiantSceneResponse::Message { message });
}
} else if let Some(node) = self.document.write().get_node_mut(id) {
} else if let Some(mut node) = self.document.write().get_node_mut(id) {
if let Some(component) = node.get_component_mut::<TransformComponent>() {
component.transform_xy(&position.into());
component.transform_scale(&scale.into());
Expand All @@ -179,7 +180,7 @@ impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>, N: RadiantNode
position,
scale,
} => {
if let Some(node) = self.document.write().get_node_mut(id) {
if let Some(mut node) = self.document.write().get_node_mut(id) {
if let Some(component) = node.get_component_mut::<TransformComponent>() {
component.set_position(&position.into());
component.set_scale(&scale.into());
Expand All @@ -191,15 +192,15 @@ impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>, N: RadiantNode
}
}
RadiantSceneMessage::SetFillColor { id, fill_color } => {
if let Some(node) = self.document_mut().get_node_mut(id) {
if let Some(mut node) = self.document_mut().get_node_mut(id) {
if let Some(component) = node.get_component_mut::<ColorComponent>() {
component.set_fill_color(fill_color);
node.set_needs_tessellation(true);
}
}
}
RadiantSceneMessage::SetStrokeColor { id, stroke_color } => {
if let Some(node) = self.document_mut().get_node_mut(id) {
if let Some(mut node) = self.document_mut().get_node_mut(id) {
if let Some(component) = node.get_component_mut::<ColorComponent>() {
component.set_stroke_color(stroke_color);
node.set_needs_tessellation(true);
Expand All @@ -214,7 +215,7 @@ impl<M: From<RadiantSceneMessage> + TryInto<RadiantSceneMessage>, N: RadiantNode
Some(id) => Some(id),
None => self.document.read().selected_node_id,
} {
if let Some(node) = self.document.write().get_node_mut(id) {
if let Some(mut node) = self.document.write().get_node_mut(id) {
if node.handle_key_down(key) {
self.interaction_manager
.update_interactions(node, &self.screen_descriptor);
Expand Down
1 change: 1 addition & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ radiantkit-path = { version = "0.0.1", path = "../crates/path" }
radiantkit-winit = { version = "0.0.1", path = "../crates/winit" }
macro_magic = "0.5.0"
radiantkit-collaboration = { version = "0.0.1", path = "../crates/collaboration" }
parking_lot = { version = "0.12.1", features = ["serde"] }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
radiantkit-video = { version = "0.0.1", path = "../crates/video", optional = true }
Expand Down
8 changes: 4 additions & 4 deletions runtime/pkg/radiantkit.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,11 @@ export interface InitOutput {
readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __wbindgen_export_2: WebAssembly.Table;
readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h787624fb7be6d3c7: (a: number, b: number, c: number) => void;
readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h2bac0756e820649c: (a: number, b: number) => void;
readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h4fb0e95bb6198ae7: (a: number, b: number, c: number) => void;
readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h3245379ba746818e: (a: number, b: number) => void;
readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5234d6fbfa4fe934: (a: number, b: number, c: number) => void;
readonly wasm_bindgen__convert__closures__invoke1_mut__h1f21f321b2342d6f: (a: number, b: number, c: number) => void;
readonly wasm_bindgen__convert__closures__invoke0_mut__h6e5c5b1e5a05efab: (a: number, b: number) => void;
readonly wasm_bindgen__convert__closures__invoke1_mut__h08d52ce9fda41a9d: (a: number, b: number, c: number) => void;
readonly wasm_bindgen__convert__closures__invoke0_mut__h63b5a1009b247d3f: (a: number, b: number) => void;
readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h7f0e0b13653e5123: (a: number, b: number, c: number) => void;
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
readonly __wbindgen_exn_store: (a: number) => void;
Expand Down
Loading

0 comments on commit 9231778

Please sign in to comment.