Skip to content
Snippets Groups Projects
optical.rs 6.98 KiB
Newer Older
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");
    // }
}