use crate::analyzer::AnalyzerType; use crate::dottable::Dottable; use crate::error::OpossumError; use crate::lightdata::LightData; use crate::optic_ports::OpticPorts; use core::fmt::Debug; use std::any::Any; use std::collections::HashMap; pub type LightResult = HashMap<String, Option<LightData>>; type Result<T> = std::result::Result<T, OpossumError>; pub struct OpticNodeCommon { pub name: String, pub ports: OpticPorts, } /// An [`OpticNode`] is the basic struct representing an optical component. // pub struct OpticNode { // name: String, // node: Box<dyn OpticComponent>, // ports: OpticPorts, // } // impl OpticNode { // /// Creates a new [`OpticNode`]. The concrete type of the component must be given while using the `new` function. // /// The node type ist a struct implementing the [`Optical`] trait. Since the size of the node type is not known at compile time it must be added as `Box<nodetype>`. // /// // /// # Examples // /// // /// ```rust // /// use opossum::optic_node::OpticNode; // /// use opossum::nodes::Dummy; // /// // /// let node=OpticNode::new("My node", Dummy::default()); // /// ``` // pub fn new<T: OpticComponent + 'static>(name: &str, node_type: T) -> Self { // let ports = node_type.ports(); // Self { // name: name.into(), // node: Box::new(node_type), // ports, // } // } // /// Returns a string representation of the [`OpticNode`] in `graphviz` format including port visualization. // /// This function is normally called by the top-level `to_dot`function within `OpticScenery`. // pub fn to_dot(&self, node_index: &str, parent_identifier: String) -> Result<String> { // self.node.to_dot( // node_index, // &self.name, // self.inverted(), // &self.node.ports(), // parent_identifier, // ) // } // // pub fn analyze( // // &mut self, // // incoming_data: LightResult, // // analyzer_type: &AnalyzerType, // // ) -> Result<LightResult> { // // self.node.analyze(incoming_data, analyzer_type) // // } // pub fn export_data(&self) { // let file_name = self.name.to_owned() + ".svg"; // self.node.export_data(&file_name); // } // } // impl Debug for OpticNode { // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // write!(f, "{} - {:?}", self.name, self.node) // } // } /// This is the basic trait that must be implemented by all concrete optical components. pub trait Optical: Dottable { /// Sets the name of this [`Optical`]. fn set_name(&mut self, _name: &str) {} /// Returns a reference to the name of this [`Optical`]. fn name(&self) -> &str { "unknown" } /// Return the type of the optical component (lens, filter, ...). The default implementation returns "undefined". fn node_type(&self) -> &str { "undefined" } /// Return the available (input & output) ports of this [`Optical`]. fn ports(&self) -> OpticPorts { OpticPorts::default() } /// Perform an analysis of this element. The type of analysis is given by an [`AnalyzerType`]. /// /// This function is normally only called by [`OpticScenery::analyze()`](crate::optic_scenery::OpticScenery::analyze()). /// /// # Errors /// /// This function will return an error if internal element-specific errors occur and the analysis cannot be performed. fn analyze( &mut self, _incoming_data: LightResult, _analyzer_type: &AnalyzerType, ) -> Result<LightResult> { print!("{}: No analyze function defined.", self.node_type()); Ok(LightResult::default()) } fn export_data(&self, _file_name: &str) { println!( "no export_data function implemented for nodetype <{}>", self.node_type() ) } /// Returns `true` if the [`Optical`] represents a detector which can report analysis data. fn is_detector(&self) -> bool { false } /// Mark this [`Optical`] as inverted. fn set_inverted(&mut self, _inverted: bool) { // self.ports.set_inverted(inverted); // self.node.set_inverted(inverted); } /// Returns `true` if this [`Optical`] is inverted. fn inverted(&self) -> bool { false } } impl Debug for dyn Optical { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{} - {}", self.name(), self.node_type()) } } pub trait OpticComponent: Optical + Debug + Any + 'static { fn upcast_any_ref(self: &'_ Self) -> &'_ dyn Any; } impl<T: Optical + Debug + Any + 'static> OpticComponent for T { #[inline] fn upcast_any_ref(self: &'_ Self) -> &'_ dyn Any { self } } impl dyn OpticComponent + 'static { #[inline] pub fn downcast_ref<T: 'static>(self: &'_ Self) -> Option<&'_ T> { self.upcast_any_ref().downcast_ref::<T>() } } #[cfg(test)] mod test { //use super::OpticNode; use crate::nodes::{Detector, Dummy}; // #[test] // fn new() { // let node = OpticNode::new("Test", Dummy::default()); // assert_eq!(node.name, "Test"); // assert_eq!(node.inverted(), false); // } // #[test] // fn set_name() { // let mut node = OpticNode::new("Test", Dummy::default()); // node.set_name("Test2".into()); // assert_eq!(node.name, "Test2") // } // #[test] // fn name() { // let node = OpticNode::new("Test", Dummy::default()); // assert_eq!(node.name(), "Test") // } // #[test] // fn set_inverted() { // let mut node = OpticNode::new("Test", Dummy::default()); // node.set_inverted(true); // assert_eq!(node.inverted(), true) // } // #[test] // fn inverted() { // let mut node = OpticNode::new("Test", Dummy::default()); // node.set_inverted(true); // assert_eq!(node.inverted(), true) // } // #[test] // fn is_detector() { // let node = OpticNode::new("Test", Dummy::default()); // assert_eq!(node.is_detector(), false); // let node = OpticNode::new("Test", Detector::default()); // assert_eq!(node.is_detector(), true) // } // #[test] // #[ignore] // fn to_dot() { // let node = OpticNode::new("Test", Dummy::default()); // assert_eq!( // node.to_dot("i0", "".to_owned()).unwrap(), // " i0 [label=\"Test\"]\n".to_owned() // ) // } // #[test] // #[ignore] // fn to_dot_inverted() { // let mut node = OpticNode::new("Test", Dummy::default()); // node.set_inverted(true); // assert_eq!( // node.to_dot("i0", "".to_owned()).unwrap(), // " i0 [label=\"Test(inv)\"]\n".to_owned() // ) // } // #[test] // fn node_type() { // let node = OpticNode::new("Test", Dummy::default()); // assert_eq!(node.node_type(), "dummy"); // } }