From c60edded40a717f0267345cab7948bd84f6581d8 Mon Sep 17 00:00:00 2001 From: Nova Date: Tue, 14 Jun 2022 20:31:46 -0400 Subject: [PATCH] refactor(node): use once_cell for aspects --- Cargo.toml | 1 + src/nodes/core.rs | 24 +++++++------- src/nodes/data.rs | 4 +-- src/nodes/field.rs | 77 ++++++++++++++++++-------------------------- src/nodes/spatial.rs | 51 ++++++++++++++++------------- 5 files changed, 75 insertions(+), 82 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b1e5e3a..aa72590 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ lazy_static = "1.4.0" mint = "0.5.9" mio = {version = "0.8.3", features = ["net", "os-poll", "os-ext"]} nanoid = "0.4.0" +once_cell = "1.12.0" parking_lot = "0.12.1" portable-atomic = {version = "0.3.0", features = ["float", "std"]} rccell = "0.1.3" diff --git a/src/nodes/core.rs b/src/nodes/core.rs index b784b1a..58f4dd1 100644 --- a/src/nodes/core.rs +++ b/src/nodes/core.rs @@ -5,7 +5,7 @@ use crate::core::client::Client; use anyhow::{anyhow, Result}; use libstardustxr::scenegraph::ScenegraphError; use nanoid::nanoid; -use parking_lot::RwLock; +use once_cell::sync::OnceCell; use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Weak as WeakArc}; @@ -27,10 +27,10 @@ pub struct Node { local_methods: DashMap>, destroyable: AtomicBool, - alias: RwLock>, - pub spatial: RwLock>>, - pub field: RwLock>>, - pub pulse_sender: RwLock>>, + alias: OnceCell, + pub spatial: OnceCell>, + pub field: OnceCell>, + pub pulse_sender: OnceCell>, } impl Node { @@ -60,10 +60,10 @@ impl Node { local_methods: Default::default(), destroyable: AtomicBool::from(destroyable), - alias: RwLock::new(None), - spatial: RwLock::new(None), - field: RwLock::new(None), - pulse_sender: RwLock::new(None), + alias: OnceCell::new(), + spatial: OnceCell::new(), + field: OnceCell::new(), + pulse_sender: OnceCell::new(), }; node.add_local_signal("destroy", Node::destroy_flex); node @@ -94,7 +94,7 @@ impl Node { method: &str, data: &[u8], ) -> Result<(), ScenegraphError> { - if let Some(alias) = self.alias.read().as_ref() { + if let Some(alias) = self.alias.get().as_ref() { if !alias.signals.contains(&method.to_string()) { return Err(ScenegraphError::SignalNotFound); } @@ -118,7 +118,7 @@ impl Node { method: &str, data: &[u8], ) -> Result, ScenegraphError> { - if let Some(alias) = self.alias.read().as_ref() { + if let Some(alias) = self.alias.get().as_ref() { if !alias.methods.contains(&method.to_string()) { return Err(ScenegraphError::MethodNotFound); } @@ -170,7 +170,7 @@ impl Alias { signals: Vec, methods: Vec, ) { - *node.alias.write() = Some(Alias { + let _ = node.alias.set(Alias { original: Arc::downgrade(original), signals, methods, diff --git a/src/nodes/data.rs b/src/nodes/data.rs index 99e615e..bb24d28 100644 --- a/src/nodes/data.rs +++ b/src/nodes/data.rs @@ -13,13 +13,13 @@ pub struct PulseSender {} impl PulseSender { pub fn add_to(node: &Arc) -> Result<()> { ensure!( - node.spatial.read().is_some(), + node.spatial.get().is_some(), "Internal: Node does not have a spatial attached!" ); let sender = PulseSender {}; let sender = PULSE_SENDER_REGISTRY.add(sender)?; - *node.pulse_sender.write() = Some(sender); + let _ = node.pulse_sender.set(sender); Ok(()) } } diff --git a/src/nodes/field.rs b/src/nodes/field.rs index 262cd06..b4a2d05 100644 --- a/src/nodes/field.rs +++ b/src/nodes/field.rs @@ -1,5 +1,5 @@ use super::core::Node; -use super::spatial::Spatial; +use super::spatial::{get_spatial_parent, Spatial}; use crate::core::client::Client; use anyhow::{anyhow, ensure, Result}; use glam::{swizzles::*, vec2, vec3, vec3a, Mat4, Vec3, Vec3A}; @@ -72,16 +72,14 @@ fn field_distance_flex(node: &Node, calling_client: Rc, data: &[u8]) -> .get_node(reference_space_path) .ok_or_else(|| anyhow!("Reference space node does not exist"))? .spatial - .read() - .as_ref() + .get() .ok_or_else(|| anyhow!("Reference space node does not have a spatial"))? .clone(); let point = flex_to_vec3!(flex_vec.idx(1)).ok_or_else(|| anyhow!("Point is invalid"))?; let distance = node .field - .read() - .as_ref() + .get() .unwrap() .distance(reference_space.as_ref(), point.into()); Ok(FlexBuffable::from(distance).build_singleton()) @@ -95,13 +93,12 @@ fn field_normal_flex(node: &Node, calling_client: Rc, data: &[u8]) -> Re .get_node(reference_space_path) .ok_or_else(|| anyhow!("Reference space node does not exist"))? .spatial - .read() - .as_ref() + .get() .ok_or_else(|| anyhow!("Reference space node does not have a spatial"))? .clone(); let point = flex_to_vec3!(flex_vec.idx(1)).ok_or_else(|| anyhow!("Point is invalid"))?; - let normal = node.field.read().as_ref().unwrap().normal( + let normal = node.field.get().as_ref().unwrap().normal( reference_space.as_ref(), point.into(), 0.001_f32, @@ -121,17 +118,16 @@ fn field_closest_point_flex( .get_node(reference_space_path) .ok_or_else(|| anyhow!("Reference space node does not exist"))? .spatial - .read() - .as_ref() + .get() .ok_or_else(|| anyhow!("Reference space node does not have a spatial"))? .clone(); let point = flex_to_vec3!(flex_vec.idx(1)).ok_or_else(|| anyhow!("Point is invalid"))?; - let closest_point = node.field.read().as_ref().unwrap().closest_point( - reference_space.as_ref(), - point.into(), - 0.001_f32, - ); + let closest_point = + node.field + .get() + .unwrap() + .closest_point(reference_space.as_ref(), point.into(), 0.001_f32); Ok(FlexBuffable::from(mint::Vector3::from(closest_point)).build_singleton()) } @@ -160,20 +156,20 @@ pub struct BoxField { impl BoxField { pub fn add_to(node: &Arc, size: Vec3) -> Result<()> { ensure!( - node.spatial.read().is_some(), + node.spatial.get().is_some(), "Internal: Node does not have a spatial attached!" ); ensure!( - node.field.read().is_none(), + node.field.get().is_none(), "Internal: Node already has a field attached!" ); let box_field = BoxField { - space: node.spatial.read().as_ref().unwrap().clone(), + space: node.spatial.get().unwrap().clone(), size: Mutex::new(size), }; box_field.add_field_methods(node); node.add_local_signal("setSize", BoxField::set_size_flex); - *node.field.write() = Some(Arc::new(Field::Box(box_field))); + let _ = node.field.set(Arc::new(Field::Box(box_field))); Ok(()) } @@ -184,7 +180,7 @@ impl BoxField { pub fn set_size_flex(node: &Node, _calling_client: Rc, data: &[u8]) -> Result<()> { let root = flexbuffers::Reader::get_root(data)?; let size = flex_to_vec3!(root).ok_or_else(|| anyhow!("Size is invalid"))?; - if let Field::Box(box_field) = node.field.read().as_ref().unwrap().as_ref() { + if let Field::Box(box_field) = node.field.get().unwrap().as_ref() { box_field.set_size(size.into()); } Ok(()) @@ -216,21 +212,21 @@ pub struct CylinderField { impl CylinderField { pub fn add_to(node: &Arc, length: f32, radius: f32) -> Result<()> { ensure!( - node.spatial.read().is_some(), + node.spatial.get().is_some(), "Internal: Node does not have a spatial attached!" ); ensure!( - node.field.read().is_none(), + node.field.get().is_none(), "Internal: Node already has a field attached!" ); let cylinder_field = CylinderField { - space: node.spatial.read().as_ref().unwrap().clone(), + space: node.spatial.get().unwrap().clone(), length: AtomicF32::new(length), radius: AtomicF32::new(radius), }; cylinder_field.add_field_methods(node); node.add_local_signal("setSize", CylinderField::set_size_flex); - *node.field.write() = Some(Arc::new(Field::Cylinder(cylinder_field))); + let _ = node.field.set(Arc::new(Field::Cylinder(cylinder_field))); Ok(()) } @@ -244,7 +240,7 @@ impl CylinderField { let flex_vec = root.get_vector()?; let length = flex_vec.idx(0).as_f32(); let radius = flex_vec.idx(1).as_f32(); - if let Field::Cylinder(cylinder_field) = node.field.read().as_ref().unwrap().as_ref() { + if let Field::Cylinder(cylinder_field) = node.field.get().unwrap().as_ref() { cylinder_field.set_size(length, radius); } Ok(()) @@ -276,20 +272,20 @@ pub struct SphereField { impl SphereField { pub fn add_to(node: &Arc, radius: f32) -> Result<()> { ensure!( - node.spatial.read().is_some(), + node.spatial.get().is_some(), "Internal: Node does not have a spatial attached!" ); ensure!( - node.field.read().is_none(), + node.field.get().is_none(), "Internal: Node already has a field attached!" ); let sphere_field = SphereField { - space: node.spatial.read().as_ref().unwrap().clone(), + space: node.spatial.get().unwrap().clone(), radius: AtomicF32::new(radius), }; sphere_field.add_field_methods(node); node.add_local_signal("setRadius", SphereField::set_radius_flex); - *node.field.write() = Some(Arc::new(Field::Sphere(sphere_field))); + let _ = node.field.set(Arc::new(Field::Sphere(sphere_field))); Ok(()) } @@ -299,7 +295,7 @@ impl SphereField { pub fn set_radius_flex(node: &Node, _calling_client: Rc, data: &[u8]) -> Result<()> { let root = flexbuffers::Reader::get_root(data)?; - if let Field::Sphere(sphere_field) = node.field.read().as_ref().unwrap().as_ref() { + if let Field::Sphere(sphere_field) = node.field.get().unwrap().as_ref() { sphere_field.set_radius(root.as_f32()); } Ok(()) @@ -333,10 +329,7 @@ pub fn create_box_field_flex(_node: &Node, calling_client: Rc, data: &[u let root = flexbuffers::Reader::get_root(data)?; let flex_vec = root.get_vector()?; let node = Node::create("/field", flex_vec.idx(0).get_str()?, true); - let parent = calling_client - .scenegraph - .get_node(flex_vec.idx(1).as_str()) - .and_then(|node| node.spatial.read().clone()); + let parent = get_spatial_parent(&calling_client, flex_vec.idx(1).get_str()?)?; let transform = Mat4::from_rotation_translation( flex_to_quat!(flex_vec.idx(3)) .ok_or_else(|| anyhow!("Rotation not found"))? @@ -347,7 +340,7 @@ pub fn create_box_field_flex(_node: &Node, calling_client: Rc, data: &[u ); let size = flex_to_vec3!(flex_vec.idx(4)).ok_or_else(|| anyhow!("Size invalid"))?; let node_rc = calling_client.scenegraph.add_node(node); - Spatial::add_to(&node_rc, parent, transform)?; + Spatial::add_to(&node_rc, Some(parent), transform)?; BoxField::add_to(&node_rc, size.into())?; Ok(()) } @@ -360,10 +353,7 @@ pub fn create_cylinder_field_flex( let root = flexbuffers::Reader::get_root(data)?; let flex_vec = root.get_vector()?; let node = Node::create("/field", flex_vec.idx(0).get_str()?, true); - let parent = calling_client - .scenegraph - .get_node(flex_vec.idx(1).as_str()) - .and_then(|node| node.spatial.read().clone()); + let parent = get_spatial_parent(&calling_client, flex_vec.idx(1).get_str()?)?; let transform = Mat4::from_rotation_translation( flex_to_quat!(flex_vec.idx(3)) .ok_or_else(|| anyhow!("Rotation not found"))? @@ -375,7 +365,7 @@ pub fn create_cylinder_field_flex( let length = flex_vec.idx(0).as_f32(); let radius = flex_vec.idx(1).as_f32(); let node_rc = calling_client.scenegraph.add_node(node); - Spatial::add_to(&node_rc, parent, transform)?; + Spatial::add_to(&node_rc, Some(parent), transform)?; CylinderField::add_to(&node_rc, length, radius)?; Ok(()) } @@ -388,17 +378,14 @@ pub fn create_sphere_field_flex( let root = flexbuffers::Reader::get_root(data)?; let flex_vec = root.get_vector()?; let node = Node::create("/field", flex_vec.idx(0).get_str()?, true); - let parent = calling_client - .scenegraph - .get_node(flex_vec.idx(1).as_str()) - .and_then(|node| node.spatial.read().clone()); + let parent = get_spatial_parent(&calling_client, flex_vec.idx(1).get_str()?)?; let transform = Mat4::from_translation( flex_to_vec3!(flex_vec.idx(2)) .ok_or_else(|| anyhow!("Position not found"))? .into(), ); let node_rc = calling_client.scenegraph.add_node(node); - Spatial::add_to(&node_rc, parent, transform)?; + Spatial::add_to(&node_rc, Some(parent), transform)?; SphereField::add_to(&node_rc, flex_vec.idx(3).as_f32())?; Ok(()) } diff --git a/src/nodes/spatial.rs b/src/nodes/spatial.rs index 4eaa5d0..bf71c92 100644 --- a/src/nodes/spatial.rs +++ b/src/nodes/spatial.rs @@ -22,7 +22,7 @@ impl Spatial { transform: Mat4, ) -> Result> { ensure!( - node.spatial.read().is_none(), + node.spatial.get().is_none(), "Internal: Node already has a Spatial aspect!" ); let spatial = Spatial { @@ -33,7 +33,7 @@ impl Spatial { node.add_local_method("getTransform", Spatial::get_transform_flex); node.add_local_signal("setTransform", Spatial::set_transform_flex); let spatial_arc = Arc::new(spatial); - *node.spatial.write() = Some(spatial_arc.clone()); + let _ = node.spatial.set(spatial_arc.clone()); Ok(spatial_arc) } @@ -97,14 +97,16 @@ impl Spatial { let root = flexbuffers::Reader::get_root(data)?; let this_spatial = node .spatial - .read() - .clone() + .get() .ok_or_else(|| anyhow!("Node doesn't have a spatial?"))?; let relative_spatial = calling_client .scenegraph .get_node(root.as_str()) - .and_then(|node| node.spatial.read().clone()) - .ok_or_else(|| anyhow!("Space not found"))?; + .ok_or_else(|| anyhow!("Space not found"))? + .spatial + .get() + .ok_or_else(|| anyhow!("Reference space node is not a spatial"))? + .clone(); let (scale, rotation, position) = Spatial::space_to_space_matrix( Some(this_spatial.as_ref()), @@ -134,26 +136,32 @@ impl Spatial { .get_node(reference_space_path) .ok_or_else(|| anyhow!("Other spatial node not found"))? .spatial - .read() - .as_ref() + .get() .ok_or_else(|| anyhow!("Node is not a Spatial!"))? .clone(), ) }; - node.spatial - .read() - .as_ref() - .unwrap() - .set_local_transform_components( - reference_space_transform.as_deref(), - flex_to_vec3!(flex_vec.idx(1)).map(|v| v.into()), - flex_to_quat!(flex_vec.idx(2)).map(|v| v.into()), - flex_to_vec3!(flex_vec.idx(3)).map(|v| v.into()), - ); + node.spatial.get().unwrap().set_local_transform_components( + reference_space_transform.as_deref(), + flex_to_vec3!(flex_vec.idx(1)).map(|v| v.into()), + flex_to_quat!(flex_vec.idx(2)).map(|v| v.into()), + flex_to_vec3!(flex_vec.idx(3)).map(|v| v.into()), + ); Ok(()) } } +pub fn get_spatial_parent(calling_client: &Rc, node_path: &str) -> Result> { + Ok(calling_client + .scenegraph + .get_node(node_path) + .ok_or_else(|| anyhow!("Spatial parent node not found"))? + .spatial + .get() + .ok_or_else(|| anyhow!("Spatial parent node is not a spatial"))? + .clone()) +} + pub fn create_interface(client: Rc) { let node = Node::create("", "spatial", false); node.add_local_signal("createSpatial", create_spatial_flex); @@ -164,10 +172,7 @@ pub fn create_spatial_flex(_node: &Node, calling_client: Rc, data: &[u8] let root = flexbuffers::Reader::get_root(data)?; let flex_vec = root.get_vector()?; let spatial = Node::create("/spatial/spatial", flex_vec.idx(0).get_str()?, true); - let parent = calling_client - .scenegraph - .get_node(flex_vec.idx(1).as_str()) - .and_then(|node| node.spatial.read().clone()); + let parent = get_spatial_parent(&calling_client, flex_vec.idx(1).get_str()?)?; let transform = Mat4::from_scale_rotation_translation( flex_to_vec3!(flex_vec.idx(4)) .ok_or_else(|| anyhow!("Scale not found"))? @@ -180,6 +185,6 @@ pub fn create_spatial_flex(_node: &Node, calling_client: Rc, data: &[u8] .into(), ); let spatial_rc = calling_client.scenegraph.add_node(spatial); - Spatial::add_to(&spatial_rc, parent, transform)?; + Spatial::add_to(&spatial_rc, Some(parent), transform)?; Ok(()) }