tudelft-xray-sim 1.0.0

simulation library for the modeling assignment in the course 'Software Systems' at the TU Delft.
Documentation
use log::warn;

use crate::{Dose, Mode, Plane, Projection};

/// Controller for the X-ray planes in the system.
pub struct Controller<const IS_TWO_PLANE: bool> {
    pub(crate) frontal: Plane,
    pub(crate) lateral: Plane,
}

impl<const IS_TWO_PLANE: bool> Controller<IS_TWO_PLANE> {
    /// Get a non-mutable reference to the frontal plane.
    /// This might be useful if you want to check the state of the plane.
    #[must_use]
    pub fn frontal(&self) -> &Plane {
        &self.frontal
    }

    /// Activate the frontal plane with the given [`Dose`] and [`Mode`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
    /// # fn f(controller: &mut Controller<false>) {
    /// controller.activate_frontal(Dose::High, Mode::Video);
    ///
    /// let frontal = controller.frontal();
    /// assert!(frontal.active());
    /// assert_eq!(frontal.dose(), Dose::High);
    /// assert_eq!(frontal.mode(), Mode::Video);
    /// # }
    /// ```
    pub fn activate_frontal(&mut self, dose: Dose, mode: Mode) {
        self.frontal.set_and_activate_xray(dose, mode);
    }
}

impl Controller<false> {
    /// Deactivate all active X-ray planes.
    ///
    /// For a system with only one plane this
    /// deactivates only the frontal plane.
    ///
    /// # Examples
    ///  
    /// ```
    /// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
    /// # fn f(controller: &mut Controller<false>) {
    /// assert!(!controller.frontal().active()); // starts inactive
    /// controller.activate_frontal(Dose::Low, Mode::Image);
    /// assert!(controller.frontal().active()); // now active
    /// controller.deactivate_xray();
    /// assert!(!controller.frontal().active()); // again inactive
    /// # }
    /// ```
    pub fn deactivate_xray(&mut self) {
        self.frontal.deactivate_xray();
    }
}

impl Controller<true> {
    /// Get a non-mutable reference to the lateral plane.
    /// This might be useful if you want to check the state of the plane.
    ///
    /// This function is only available for two-plane systems,
    /// so it is only defined for [`Controller<true>`].
    #[must_use]
    pub fn lateral(&self) -> &Plane {
        &self.lateral
    }

    /// Activate the lateral plane with the given [`Dose`] and [`Mode`].
    ///
    /// This function is only available for two-plane systems,
    /// so it is only defined for [`Controller<true>`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
    /// # fn f(controller: &mut Controller<true>) {
    /// controller.activate_lateral(Dose::High, Mode::Video);
    ///
    /// let lateral = controller.lateral();
    /// assert!(lateral.active());
    /// assert_eq!(lateral.dose(), Dose::High);
    /// assert_eq!(lateral.mode(), Mode::Video);
    /// # }
    /// ```
    pub fn activate_lateral(&mut self, dose: Dose, mode: Mode) {
        self.lateral.set_and_activate_xray(dose, mode);
    }

    /// Activate both planes with the given [`Dose`] and [`Mode`].
    ///
    /// This function is only available for two-plane systems,
    /// so it is only defined for [`Controller<true>`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
    /// # fn f(controller: &mut Controller<true>) {
    /// controller.activate_biplane(Dose::Low, Mode::Video);
    ///
    /// let frontal = controller.frontal();
    /// assert!(frontal.active());
    /// assert_eq!(frontal.dose(), Dose::Low);
    /// assert_eq!(frontal.mode(), Mode::Video);
    ///
    /// let lateral = controller.lateral();
    /// assert!(lateral.active());
    /// assert_eq!(lateral.dose(), Dose::Low);
    /// assert_eq!(lateral.mode(), Mode::Video);
    /// # }
    /// ```
    pub fn activate_biplane(&mut self, dose: Dose, mode: Mode) {
        self.frontal.set_and_activate_xray(dose, mode);
        self.lateral.set_and_activate_xray(dose, mode);
    }

    /// Activate the X-ray planes based on the projection with
    /// the given [`Dose`] and [`Mode`].
    ///
    /// This function is only available for two-plane systems,
    /// so it is only defined for [`Controller<true>`].
    pub fn activate_xray(&mut self, projection: Projection, dose: Dose, mode: Mode) {
        match projection {
            Projection::Frontal => self.activate_frontal(dose, mode),
            Projection::Lateral => self.activate_lateral(dose, mode),
            Projection::Biplane => self.activate_biplane(dose, mode),
        }
    }

    /// Deactivate all active X-ray planes.
    ///
    /// Logs a warning if there are no active planes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
    /// # fn f(controller: &mut Controller<true>) {
    /// // activate both
    /// controller.activate_biplane(Dose::High, Mode::Video);
    /// assert!(controller.frontal().active());
    /// assert!(controller.lateral().active());
    ///
    /// // deactivate both
    /// controller.deactivate_xray();
    /// assert!(!controller.frontal().active());
    /// assert!(!controller.lateral().active());
    /// # }
    /// ```
    ///
    /// ```
    /// # use tudelft_xray_sim::{Controller, Plane, Projection, Dose, Mode};
    /// # fn f(controller: &mut Controller<true>) {
    /// // activate lateral
    /// controller.activate_lateral(Dose::Low, Mode::Video);
    /// assert!(!controller.frontal().active());
    /// assert!(controller.lateral().active());
    ///
    /// // deactivate lateral
    /// controller.deactivate_xray();
    /// assert!(!controller.frontal().active());
    /// assert!(!controller.lateral().active());
    ///
    /// // deactivate again - this logs a warning
    /// controller.deactivate_xray();
    /// # }
    /// ```
    pub fn deactivate_xray(&mut self) {
        let mut deactivated = false;
        if self.frontal.active() {
            self.frontal.deactivate_xray();
            deactivated = true;
        }
        if self.lateral.active() {
            self.lateral.deactivate_xray();
            deactivated = true;
        }
        if !deactivated {
            warn!("Tried deactivating X-ray planes but they were all already inactive");
        }
    }
}