Skip to content
Snippets Groups Projects
source.rs 4.93 KiB
Newer Older
Udo Eisenbarth's avatar
Udo Eisenbarth committed
#![warn(missing_docs)]
use std::collections::HashMap;
use std::fmt::Debug;
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    dottable::Dottable,
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    error::{OpmResult, OpossumError},
    lightdata::LightData,
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    optic_ports::OpticPorts,
    optical::{LightResult, Optical},
    properties::{Properties, Property, Proptype},
/// This node represents a source of light.
///
Udo Eisenbarth's avatar
Udo Eisenbarth committed
/// Hence it has only one output port (out1) and no input ports. Source nodes usually are the first nodes of an [`OpticScenery`](crate::OpticScenery).
Udo Eisenbarth's avatar
Udo Eisenbarth committed
///
/// ## Optical Ports
///   - Inputs
///     - none
///   - Outputs
///     - `out1`
Udo Eisenbarth's avatar
Udo Eisenbarth committed
///
/// ## Properties
///   - `name`
///   - `light data`
///
/// **Note**: This node does not have the `inverted` property since it has only one output port.
Udo Eisenbarth's avatar
Udo Eisenbarth committed
pub struct Source {
    props: Properties,
}
fn create_default_props() -> Properties {
    let mut props = Properties::default();
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    props.set("name", "source".into());
    props.set(
        "light data",
        Property {
            prop: Proptype::LightData(None),
        },
    );
    props
impl Default for Source {
    fn default() -> Self {
        Self {
            props: create_default_props(),
        }
    }
}
Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Source {
    /// Creates a new [`Source`].
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    ///
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    /// The light to be emitted from this source is defined in a [`LightData`] structure.
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    ///
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    /// ## Example
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    ///
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    /// ```rust
    /// use opossum::{
    /// lightdata::{DataEnergy, LightData},
    /// nodes::Source,
    /// spectrum::create_he_ne_spectrum};
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    ///
    /// let source=Source::new("My Source", LightData::Energy(DataEnergy {spectrum: create_he_ne_spectrum(1.0)}));
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    /// ```
    pub fn new(name: &str, light: LightData) -> Self {
        let mut props = create_default_props();
Udo Eisenbarth's avatar
Udo Eisenbarth committed
        props.set("name", name.into());
        props.set(
            "light data",
            Property {
                prop: Proptype::LightData(Some(light.clone())),
            },
        );
        Source { props }
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    /// Sets the light data of this [`Source`]. The [`LightData`] provided here represents the input data of an `OpticScenery`.
    pub fn set_light_data(&mut self, light_data: LightData) {
        self.props.set(
            "light data",
            Property {
                prop: Proptype::LightData(Some(light_data.clone())),
            },
        );

impl Debug for Source {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let light_prop = self.props.get("light data").unwrap();
        let data = if let Proptype::LightData(data) = &light_prop.prop {
            data
        } else {
            &None
        };
        match data {
            Some(data) => write!(f, "{}", data),
            None => write!(f, "no data"),
        }
    }
}

Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Optical for Source {
    fn node_type(&self) -> &str {
        "light source"
    }
    fn name(&self) -> &str {
        if let Proptype::String(name) = &self.props.get("name").unwrap().prop {
            name
        } else {
            "light source"
        }
    }
    fn ports(&self) -> OpticPorts {
        let mut ports = OpticPorts::new();
        ports.add_output("out1").unwrap();
        ports
    }
    fn analyze(
        &mut self,
        _incoming_edges: LightResult,
        _analyzer_type: &crate::analyzer::AnalyzerType,
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    ) -> OpmResult<LightResult> {
        let light_prop = self.props.get("light data").unwrap();
        let data = if let Proptype::LightData(data) = &light_prop.prop {
            Ok(HashMap::from([("out1".into(), data.to_owned())]))
            Err(OpossumError::Analysis("no input data available".into()))
    fn properties(&self) -> &Properties {
        &self.props
    }
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    fn set_property(&mut self, name: &str, prop: Property) -> OpmResult<()> {
        if self.props.set(name, prop).is_none() {
            Err(OpossumError::Other("property not defined".into()))
        } else {
            Ok(())
        }
    }
Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Dottable for Source {
    fn node_color(&self) -> &str {
        "slateblue"
    }
#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn default() {
        let node = Source::default();
        assert_eq!(node.name(), "source");
        assert_eq!(node.node_type(), "light source");
        assert_eq!(node.is_detector(), false);
        assert_eq!(node.inverted(), false);
        assert_eq!(node.node_color(), "slateblue");
        assert!(node.as_group().is_err());
    }
    #[test]
    fn new() {
        let source = Source::new("test", LightData::Fourier);
        assert_eq!(source.name(), "test");
    }
    #[test]
    fn not_invertable() {
        let mut node = Source::default();
        assert!(node.set_property("inverted", true.into()).is_err());
    }
    #[test]
    fn ports() {
        let detector = Source::default();
        assert!(detector.ports().inputs().is_empty());
        assert_eq!(detector.ports().outputs(), vec!["out1"]);
    }
}