use super::{Aspect, Node}; use crate::core::{client::Client, registry::Registry}; use color_eyre::eyre::Result; use std::{ ops::Add, sync::{Arc, Weak}, }; #[derive(Debug, Default, Clone)] pub struct AliasInfo { pub(super) server_signals: Vec, pub(super) server_methods: Vec, pub(super) client_signals: Vec, } impl Add for AliasInfo { type Output = AliasInfo; fn add(mut self, mut rhs: Self) -> Self::Output { self.server_signals.append(&mut rhs.server_signals); self.server_methods.append(&mut rhs.server_methods); self.client_signals.append(&mut rhs.client_signals); self } } #[derive(Debug)] pub struct Alias { pub(super) node: Weak, pub(super) original: Weak, pub(super) info: AliasInfo, } impl Alias { pub fn create( original: &Arc, client: &Arc, info: AliasInfo, list: Option<&AliasList>, ) -> Result> { let node = Node::generate(client, true).add_to_scenegraph()?; Self::add_to(&node, original, info)?; if let Some(list) = list { list.add(&node); } Ok(node) } pub fn create_with_id( original: &Arc, client: &Arc, new_id: u64, info: AliasInfo, list: Option<&AliasList>, ) -> Result> { let node = Node::from_id(client, new_id, true).add_to_scenegraph()?; Self::add_to(&node, original, info)?; if let Some(list) = list { list.add(&node); } Ok(node) } fn add_to(new_node: &Arc, original: &Arc, info: AliasInfo) -> Result<()> { let alias = Alias { node: Arc::downgrade(new_node), original: Arc::downgrade(original), info, }; let alias = original.aliases.add(alias); new_node.add_aspect_raw(alias); Ok(()) } } impl Aspect for Alias { const NAME: &'static str = "Alias"; } pub fn get_original(node: Arc, stop_on_disabled: bool) -> Option> { let Ok(alias) = node.get_aspect::() else { return Some(node); }; if stop_on_disabled && !node.enabled() { return None; } get_original(alias.original.upgrade()?, stop_on_disabled) } pub fn links_to(alias: Arc, original: Weak) -> bool { let Ok(alias) = alias.get_aspect::() else { return false; }; if alias.original.ptr_eq(&original) { return true; } let Some(original_strong) = alias.original.upgrade() else { return false; }; links_to(original_strong, original) } #[derive(Debug, Default, Clone)] pub struct AliasList(Registry); impl AliasList { fn add(&self, node: &Arc) { self.0.add_raw(node); } pub fn get_from_original_node(&self, original: Weak) -> Option> { self.0 .get_valid_contents() .into_iter() .find(move |node| links_to(node.clone(), original.clone())) } pub fn get_from_aspect(&self, aspect: &A) -> Option> { self.0.get_valid_contents().into_iter().find(|node| { let Some(node) = get_original(node.clone(), false) else { return false; }; let Ok(aspect2) = node.get_aspect::() else { return false; }; Arc::as_ptr(&aspect2) == (aspect as *const A) }) } pub fn get_aliases(&self) -> Vec> { self.0.get_valid_contents() } pub fn remove_aspect(&self, aspect: &A) { self.0.retain(|node| { let Some(original) = get_original(node.clone(), false) else { return false; }; let Ok(aspect2) = original.get_aspect::() else { return false; }; Arc::as_ptr(&aspect2) != (aspect as *const A) }) } } impl Drop for AliasList { fn drop(&mut self) { for node in self.0.take_valid_contents() { node.destroy(); } } }