diff --git a/src/core/nodelist.rs b/src/core/nodelist.rs index d415153..988c828 100644 --- a/src/core/nodelist.rs +++ b/src/core/nodelist.rs @@ -1,4 +1,4 @@ -use crate::nodes::core::Node; +use crate::nodes::Node; use parking_lot::Mutex; use std::sync::Weak; diff --git a/src/core/scenegraph.rs b/src/core/scenegraph.rs index 8551ecb..a0d74d2 100644 --- a/src/core/scenegraph.rs +++ b/src/core/scenegraph.rs @@ -1,5 +1,5 @@ use crate::core::client::Client; -use crate::nodes::core::Node; +use crate::nodes::Node; use anyhow::Result; use libstardustxr::scenegraph; use libstardustxr::scenegraph::ScenegraphError; diff --git a/src/nodes/alias.rs b/src/nodes/alias.rs new file mode 100644 index 0000000..9a48d5b --- /dev/null +++ b/src/nodes/alias.rs @@ -0,0 +1,35 @@ +use super::Node; +use std::sync::{Arc, Weak}; + +#[allow(dead_code)] +pub struct Alias { + pub(super) node: Weak, + pub original: Weak, + + pub(super) local_signals: Vec<&'static str>, + pub(super) local_methods: Vec<&'static str>, + pub(super) remote_signals: Vec<&'static str>, + pub(super) remote_methods: Vec<&'static str>, +} +impl Alias { + pub fn add_to( + node: &Arc, + original: &Arc, + local_signals: Vec<&'static str>, + local_methods: Vec<&'static str>, + remote_signals: Vec<&'static str>, + remote_methods: Vec<&'static str>, + ) -> Arc { + let alias = Alias { + node: Arc::downgrade(node), + original: Arc::downgrade(original), + local_signals, + local_methods, + remote_signals, + remote_methods, + }; + let alias = original.aliases.add(alias); + let _ = node.alias.set(alias.clone()); + alias + } +} diff --git a/src/nodes/core.rs b/src/nodes/core.rs deleted file mode 100644 index b764337..0000000 --- a/src/nodes/core.rs +++ /dev/null @@ -1,227 +0,0 @@ -use super::data::{PulseReceiver, PulseSender}; -use super::field::Field; -use super::input::{InputHandler, InputMethod}; -use super::item::{Item, ItemAcceptor, ItemUI}; -use super::model::Model; -use super::spatial::Spatial; -use crate::core::client::Client; -use crate::core::registry::Registry; -use anyhow::{anyhow, Result}; -use libstardustxr::scenegraph::ScenegraphError; -use nanoid::nanoid; -use once_cell::sync::OnceCell; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Weak}; -use std::vec::Vec; - -use core::hash::BuildHasherDefault; -use dashmap::DashMap; -use rustc_hash::FxHasher; - -pub type Signal = fn(&Node, Arc, &[u8]) -> Result<()>; -pub type Method = fn(&Node, Arc, &[u8]) -> Result>; - -pub struct Node { - pub(super) uid: String, - path: String, - // trailing_slash_pos: usize, - local_signals: DashMap>, - local_methods: DashMap>, - destroyable: AtomicBool, - - pub alias: OnceCell>, - aliases: Registry, - - pub spatial: OnceCell>, - pub field: OnceCell>, - pub model: OnceCell>, - pub pulse_sender: OnceCell>, - pub pulse_receiver: OnceCell>, - pub item: OnceCell>, - pub item_acceptor: OnceCell>, - pub item_ui: OnceCell>, - pub input_method: OnceCell>, - pub input_handler: OnceCell>, - - pub(crate) client: Weak, -} - -impl Node { - pub fn get_client(&self) -> Arc { - self.client.upgrade().unwrap() - } - // pub fn get_name(&self) -> &str { - // &self.path[self.trailing_slash_pos + 1..] - // } - pub fn get_path(&self) -> &str { - self.path.as_str() - } - pub fn is_destroyable(&self) -> bool { - self.destroyable.load(Ordering::Relaxed) - } - - pub fn create(client: &Arc, parent: &str, name: &str, destroyable: bool) -> Self { - let mut path = parent.to_string(); - path.push('/'); - path.push_str(name); - let node = Node { - uid: nanoid!(), - client: Arc::downgrade(client), - path, - // trailing_slash_pos: parent.len(), - local_signals: Default::default(), - local_methods: Default::default(), - destroyable: AtomicBool::from(destroyable), - - alias: OnceCell::new(), - aliases: Registry::new(), - - spatial: OnceCell::new(), - field: OnceCell::new(), - model: OnceCell::new(), - pulse_sender: OnceCell::new(), - pulse_receiver: OnceCell::new(), - item: OnceCell::new(), - item_acceptor: OnceCell::new(), - item_ui: OnceCell::new(), - input_method: OnceCell::new(), - input_handler: OnceCell::new(), - }; - node.add_local_signal("destroy", Node::destroy_flex); - node - } - pub fn add_to_scenegraph(self) -> Arc { - self.get_client().scenegraph.add_node(self) - } - pub fn destroy(&self) { - let _ = self.get_client().scenegraph.remove_node(self.get_path()); - } - - pub fn destroy_flex(node: &Node, _calling_client: Arc, _data: &[u8]) -> Result<()> { - if node.is_destroyable() { - node.destroy(); - } - Ok(()) - } - - pub fn add_local_signal(&self, name: &str, signal: Signal) { - self.local_signals.insert(name.to_string(), signal); - } - pub fn add_local_method(&self, name: &str, method: Method) { - self.local_methods.insert(name.to_string(), method); - } - - pub fn send_local_signal( - &self, - calling_client: Arc, - method: &str, - data: &[u8], - ) -> Result<(), ScenegraphError> { - if let Some(alias) = self.alias.get().as_ref() { - if !alias.local_signals.iter().any(|e| e == &method) { - return Err(ScenegraphError::SignalNotFound); - } - alias - .original - .upgrade() - .ok_or(ScenegraphError::BrokenAlias)? - .send_local_signal(calling_client, method, data) - } else { - let signal = self - .local_signals - .get(method) - .ok_or(ScenegraphError::SignalNotFound)?; - signal(self, calling_client, data) - .map_err(|error| ScenegraphError::SignalError { error }) - } - } - pub fn execute_local_method( - &self, - calling_client: Arc, - method: &str, - data: &[u8], - ) -> Result, ScenegraphError> { - if let Some(alias) = self.alias.get().as_ref() { - if !alias.local_methods.iter().any(|e| e == &method) { - return Err(ScenegraphError::MethodNotFound); - } - alias - .original - .upgrade() - .ok_or(ScenegraphError::BrokenAlias)? - .execute_local_method(calling_client, method, data) - } else { - let method = self - .local_methods - .get(method) - .ok_or(ScenegraphError::MethodNotFound)?; - method(self, calling_client, data) - .map_err(|error| ScenegraphError::MethodError { error }) - } - } - pub fn send_remote_signal(&self, method: &str, data: &[u8]) -> Result<()> { - self.aliases - .get_valid_contents() - .iter() - .filter(|alias| alias.remote_signals.iter().any(|e| e == &method)) - .for_each(|alias| { - let _ = alias - .node - .upgrade() - .unwrap() - .send_remote_signal(method, data); - }); - let client = self.get_client(); - let path = self.path.clone(); - let method = method.to_string(); - let data = data.to_vec(); - - if let Some(messenger) = client.messenger.as_ref() { - let _ = messenger.send_remote_signal(path.as_str(), method.as_str(), data.as_slice()); - } - Ok(()) - } - pub async fn execute_remote_method(&self, method: &str, data: Vec) -> Result> { - match self.get_client().messenger.as_ref() { - None => Err(anyhow!("Messenger does not exist for this node's client")), - Some(messenger) => { - messenger - .execute_remote_method(self.path.as_str(), method, &data) - .await - } - } - } -} - -#[allow(dead_code)] -pub struct Alias { - node: Weak, - pub original: Weak, - - local_signals: Vec<&'static str>, - local_methods: Vec<&'static str>, - remote_signals: Vec<&'static str>, - remote_methods: Vec<&'static str>, -} -impl Alias { - pub fn add_to( - node: &Arc, - original: &Arc, - local_signals: Vec<&'static str>, - local_methods: Vec<&'static str>, - remote_signals: Vec<&'static str>, - remote_methods: Vec<&'static str>, - ) -> Arc { - let alias = Alias { - node: Arc::downgrade(node), - original: Arc::downgrade(original), - local_signals, - local_methods, - remote_signals, - remote_methods, - }; - let alias = original.aliases.add(alias); - let _ = node.alias.set(alias.clone()); - alias - } -} diff --git a/src/nodes/data.rs b/src/nodes/data.rs index 3c5b890..9adcd6e 100644 --- a/src/nodes/data.rs +++ b/src/nodes/data.rs @@ -1,6 +1,6 @@ -use super::core::{Alias, Node}; use super::field::Field; use super::spatial::{get_spatial_parent_flex, get_transform_pose_flex, Spatial}; +use super::{Alias, Node}; use crate::core::client::Client; use crate::core::nodelist::LifeLinkedNodeList; use crate::core::registry::Registry; diff --git a/src/nodes/field.rs b/src/nodes/field.rs index c419c76..5752724 100644 --- a/src/nodes/field.rs +++ b/src/nodes/field.rs @@ -1,5 +1,5 @@ -use super::core::Node; use super::spatial::{get_spatial_parent_flex, Spatial}; +use super::Node; use crate::core::client::Client; use anyhow::{anyhow, ensure, Result}; use glam::{swizzles::*, vec2, vec3, vec3a, Mat4, Vec3, Vec3A}; diff --git a/src/nodes/hmd.rs b/src/nodes/hmd.rs index 6e1f5a6..6907aea 100644 --- a/src/nodes/hmd.rs +++ b/src/nodes/hmd.rs @@ -1,7 +1,4 @@ -use super::{ - core::{Alias, Node}, - spatial::Spatial, -}; +use super::{alias::Alias, spatial::Spatial, Node}; use crate::core::client::{Client, INTERNAL_CLIENT}; use glam::{vec3, Mat4}; use std::sync::Arc; diff --git a/src/nodes/input/mod.rs b/src/nodes/input/mod.rs index 7336bff..7a3d14a 100644 --- a/src/nodes/input/mod.rs +++ b/src/nodes/input/mod.rs @@ -1,9 +1,9 @@ pub mod pointer; use self::pointer::Pointer; -use super::core::Node; use super::field::Field; use super::spatial::{get_spatial_parent_flex, get_transform_pose_flex, Spatial}; +use super::Node; use crate::core::client::Client; use crate::core::eventloop::FRAME; use crate::core::registry::Registry; diff --git a/src/nodes/item.rs b/src/nodes/item.rs index dd6d526..3a7d3a5 100644 --- a/src/nodes/item.rs +++ b/src/nodes/item.rs @@ -1,6 +1,6 @@ -use super::core::{Alias, Node}; use super::field::Field; use super::spatial::{get_spatial_parent_flex, get_transform_pose_flex, Spatial}; +use super::{Alias, Node}; use crate::core::client::{Client, INTERNAL_CLIENT}; use crate::core::nodelist::LifeLinkedNodeList; use crate::core::registry::Registry; diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index d27a014..a843143 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -1,4 +1,4 @@ -pub mod core; +pub mod alias; pub mod data; pub mod field; pub mod hmd; @@ -7,3 +7,201 @@ pub mod item; pub mod model; pub mod root; pub mod spatial; + +use anyhow::{anyhow, Result}; +use libstardustxr::scenegraph::ScenegraphError; +use nanoid::nanoid; +use once_cell::sync::OnceCell; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Weak}; +use std::vec::Vec; + +use core::hash::BuildHasherDefault; +use dashmap::DashMap; +use rustc_hash::FxHasher; + +use crate::core::client::Client; +use crate::core::registry::Registry; + +use self::alias::Alias; +use self::data::{PulseReceiver, PulseSender}; +use self::field::Field; +use self::input::{InputHandler, InputMethod}; +use self::item::{Item, ItemAcceptor, ItemUI}; +use self::model::Model; +use self::spatial::Spatial; + +pub type Signal = fn(&Node, Arc, &[u8]) -> Result<()>; +pub type Method = fn(&Node, Arc, &[u8]) -> Result>; + +pub struct Node { + pub(super) uid: String, + path: String, + // trailing_slash_pos: usize, + local_signals: DashMap>, + local_methods: DashMap>, + destroyable: AtomicBool, + + pub alias: OnceCell>, + aliases: Registry, + + pub spatial: OnceCell>, + pub field: OnceCell>, + pub model: OnceCell>, + pub pulse_sender: OnceCell>, + pub pulse_receiver: OnceCell>, + pub item: OnceCell>, + pub item_acceptor: OnceCell>, + pub item_ui: OnceCell>, + pub input_method: OnceCell>, + pub input_handler: OnceCell>, + + pub(crate) client: Weak, +} + +impl Node { + pub fn get_client(&self) -> Arc { + self.client.upgrade().unwrap() + } + // pub fn get_name(&self) -> &str { + // &self.path[self.trailing_slash_pos + 1..] + // } + pub fn get_path(&self) -> &str { + self.path.as_str() + } + pub fn is_destroyable(&self) -> bool { + self.destroyable.load(Ordering::Relaxed) + } + + pub fn create(client: &Arc, parent: &str, name: &str, destroyable: bool) -> Self { + let mut path = parent.to_string(); + path.push('/'); + path.push_str(name); + let node = Node { + uid: nanoid!(), + client: Arc::downgrade(client), + path, + // trailing_slash_pos: parent.len(), + local_signals: Default::default(), + local_methods: Default::default(), + destroyable: AtomicBool::from(destroyable), + + alias: OnceCell::new(), + aliases: Registry::new(), + + spatial: OnceCell::new(), + field: OnceCell::new(), + model: OnceCell::new(), + pulse_sender: OnceCell::new(), + pulse_receiver: OnceCell::new(), + item: OnceCell::new(), + item_acceptor: OnceCell::new(), + item_ui: OnceCell::new(), + input_method: OnceCell::new(), + input_handler: OnceCell::new(), + }; + node.add_local_signal("destroy", Node::destroy_flex); + node + } + pub fn add_to_scenegraph(self) -> Arc { + self.get_client().scenegraph.add_node(self) + } + pub fn destroy(&self) { + let _ = self.get_client().scenegraph.remove_node(self.get_path()); + } + + pub fn destroy_flex(node: &Node, _calling_client: Arc, _data: &[u8]) -> Result<()> { + if node.is_destroyable() { + node.destroy(); + } + Ok(()) + } + + pub fn add_local_signal(&self, name: &str, signal: Signal) { + self.local_signals.insert(name.to_string(), signal); + } + pub fn add_local_method(&self, name: &str, method: Method) { + self.local_methods.insert(name.to_string(), method); + } + + pub fn send_local_signal( + &self, + calling_client: Arc, + method: &str, + data: &[u8], + ) -> Result<(), ScenegraphError> { + if let Some(alias) = self.alias.get() { + if !alias.local_signals.iter().any(|e| e == &method) { + return Err(ScenegraphError::SignalNotFound); + } + alias + .original + .upgrade() + .ok_or(ScenegraphError::BrokenAlias)? + .send_local_signal(calling_client, method, data) + } else { + let signal = self + .local_signals + .get(method) + .ok_or(ScenegraphError::SignalNotFound)?; + signal(self, calling_client, data) + .map_err(|error| ScenegraphError::SignalError { error }) + } + } + pub fn execute_local_method( + &self, + calling_client: Arc, + method: &str, + data: &[u8], + ) -> Result, ScenegraphError> { + if let Some(alias) = self.alias.get() { + if !alias.local_methods.iter().any(|e| e == &method) { + return Err(ScenegraphError::MethodNotFound); + } + alias + .original + .upgrade() + .ok_or(ScenegraphError::BrokenAlias)? + .execute_local_method(calling_client, method, data) + } else { + let method = self + .local_methods + .get(method) + .ok_or(ScenegraphError::MethodNotFound)?; + method(self, calling_client, data) + .map_err(|error| ScenegraphError::MethodError { error }) + } + } + pub fn send_remote_signal(&self, method: &str, data: &[u8]) -> Result<()> { + self.aliases + .get_valid_contents() + .iter() + .filter(|alias| alias.remote_signals.iter().any(|e| e == &method)) + .for_each(|alias| { + let _ = alias + .node + .upgrade() + .unwrap() + .send_remote_signal(method, data); + }); + let client = self.get_client(); + let path = self.path.clone(); + let method = method.to_string(); + let data = data.to_vec(); + + if let Some(messenger) = client.messenger.as_ref() { + let _ = messenger.send_remote_signal(path.as_str(), method.as_str(), data.as_slice()); + } + Ok(()) + } + pub async fn execute_remote_method(&self, method: &str, data: Vec) -> Result> { + match self.get_client().messenger.as_ref() { + None => Err(anyhow!("Messenger does not exist for this node's client")), + Some(messenger) => { + messenger + .execute_remote_method(self.path.as_str(), method, &data) + .await + } + } + } +} diff --git a/src/nodes/model.rs b/src/nodes/model.rs index 13e33e8..86cd64a 100644 --- a/src/nodes/model.rs +++ b/src/nodes/model.rs @@ -1,5 +1,5 @@ -use super::core::Node; use super::spatial::{get_spatial_parent_flex, Spatial}; +use super::Node; use crate::core::client::Client; use crate::core::registry::Registry; use crate::core::resource::{NamespacedResourceID, ResourceID}; diff --git a/src/nodes/root.rs b/src/nodes/root.rs index b051683..d1fdb3b 100644 --- a/src/nodes/root.rs +++ b/src/nodes/root.rs @@ -1,5 +1,5 @@ -use super::core::Node; use super::spatial::Spatial; +use super::Node; use crate::core::client::Client; use crate::core::registry::Registry; use anyhow::Result; diff --git a/src/nodes/spatial.rs b/src/nodes/spatial.rs index b7926c3..51a982e 100644 --- a/src/nodes/spatial.rs +++ b/src/nodes/spatial.rs @@ -1,4 +1,4 @@ -use super::core::Node; +use super::Node; use crate::core::client::Client; use anyhow::{anyhow, ensure, Result}; use glam::{Mat4, Quat, Vec3}; diff --git a/src/wayland/panel_item.rs b/src/wayland/panel_item.rs index 96a37bb..2acad54 100644 --- a/src/wayland/panel_item.rs +++ b/src/wayland/panel_item.rs @@ -8,9 +8,9 @@ use crate::{ registry::Registry, }, nodes::{ - core::Node, item::{register_item_ui_flex, Item, ItemSpecialization, ItemType, TypeInfo}, spatial::Spatial, + Node, }, }; use anyhow::{anyhow, bail, Result};