ommui_data 0.39.0

OMMUI data structures
Documentation
extern crate serde;
extern crate serde_json;

use crate::arnalisa::LoadableDevice as _;
use crate::arnalisamplic::LoadableDevice as _;
use crate::ommui::LoadableDevice as _;
use crate::samplic::LoadableDevice as _;
use crate::xio::LoadableDevice as _;
use crate::xiolisa::LoadableDevice as _;
use crate::{
    file_load_json, CalibrationDescription, DeviceDescription,
    LoadPathPattern, LoadableDevice, Result, Sampling, StorableDevice,
};
use indexmap::IndexSet;
use std::path::{Path, PathBuf};

#[derive(Clone, Debug)]
pub struct Device {
    pub system_path: PathBuf,
    pub config_path: PathBuf,
    pub data_path: PathBuf,
    pub cache_path: PathBuf,
    pub product_id: String,
}

impl Device {
    pub fn system_dir(&self) -> PathBuf {
        self.system_path.clone()
    }

    pub fn config_dir(&self) -> PathBuf {
        self.config_path.clone()
    }

    pub fn data_dir(&self) -> PathBuf {
        self.data_path.clone()
    }

    pub fn cache_dir(&self) -> PathBuf {
        self.cache_path.clone()
    }

    pub fn samplic_dir(&self) -> PathBuf {
        self.system_dir().join("samplic")
    }

    pub fn description_dir(&self) -> PathBuf {
        self.system_dir().join("description")
    }

    pub fn description_calibrations_dir(&self) -> PathBuf {
        self.description_dir().join("calibration")
    }

    pub fn samplings_dir(&self) -> PathBuf {
        self.description_dir().join("sampling")
    }

    pub fn sampling_dir(&self, sampling_id: &str) -> PathBuf {
        self.samplings_dir().join(sampling_id)
    }

    pub fn description_calibration_dir(
        &self,
        calibration_id: &str,
    ) -> PathBuf {
        self.description_calibrations_dir().join(calibration_id)
    }

    pub fn device_dir(&self) -> PathBuf {
        self.description_dir().join("device")
    }
}

impl LoadableDevice for Device {
    type ArnalisaLoadableDevice = crate::arnalisa::filesystem::Device;
    type ArnalisamplicLoadableDevice =
        crate::arnalisamplic::filesystem::Device;
    type OmmuiLoadableDevice = crate::ommui::filesystem::Device;
    type SamplicLoadableDevice = crate::samplic::filesystem::Device;
    type XioLoadableDevice = crate::xio::filesystem::Device;
    type XiolisaLoadableDevice = crate::xiolisa::filesystem::Device;

    fn arnalisa(&self) -> Self::ArnalisaLoadableDevice {
        crate::arnalisa::filesystem::Device::new(self.clone())
    }

    fn arnalisamplic(&self) -> Self::ArnalisamplicLoadableDevice {
        crate::arnalisamplic::filesystem::Device::new(self.clone())
    }

    fn ommui(&self) -> Self::OmmuiLoadableDevice {
        crate::ommui::filesystem::Device::new(self.clone())
    }

    fn samplic(&self) -> Self::SamplicLoadableDevice {
        crate::samplic::filesystem::Device::new(self.clone())
    }

    fn xio(&self) -> Self::XioLoadableDevice {
        crate::xio::filesystem::Device::new(self.clone())
    }

    fn xiolisa(&self) -> Self::XiolisaLoadableDevice {
        crate::xiolisa::filesystem::Device::new(self.clone())
    }

    fn load_calibration_description_index(
        &self,
    ) -> Result<IndexSet<String>> {
        IndexSet::load_path_pattern_from_dir(
            self.description_calibrations_dir(),
            "*",
        )
    }

    fn load_calibration_description(
        &self,
        calibration_id: &str,
    ) -> Result<CalibrationDescription> {
        Ok(CalibrationDescription {
            arnalisa: self.arnalisa().load_calibration(calibration_id)?,
            ommui: self
                .ommui()
                .load_calibration_description(calibration_id)?,
            xiolisa: self.xiolisa().load_calibration(calibration_id)?,
        })
    }

    fn load_sampling_index(&self) -> Result<IndexSet<String>> {
        IndexSet::load_path_pattern_from_dir(self.samplings_dir(), "*")
    }

    fn load_sampling(&self, sampling_id: &str) -> Result<Sampling> {
        Ok(Sampling {
            arnalisa: self.arnalisa().load_sampling(sampling_id)?,
            arnalisamplic: self
                .arnalisamplic()
                .load_sampling(sampling_id)?,
            ommui: self.ommui().load_sampling(sampling_id)?,
            samplic: self.samplic().load_sampling(sampling_id)?,
            xio: self.xio().load_sampling(sampling_id)?,
        })
    }

    fn load_device_description(&self) -> Result<DeviceDescription> {
        Ok(DeviceDescription {
            samplic: self.samplic().load_device_description()?,
        })
    }

    fn load_device(&self) -> Result<crate::Device> {
        Ok(crate::Device {
            description: self.load_device_description()?,
            calibrations: self.load_calibration_descriptions()?,
            system_profiles: self.samplic().load_system_profiles()?,
            user_profiles: self.samplic().load_user_profiles()?,
            settings: {
                if self.ommui().device_settings_file().exists() {
                    Some(self.ommui().load_device_settings()?)
                } else {
                    None
                }
            },
            samplings: self.load_samplings()?,
            icons: self.samplic().load_icons()?,
            units: self.samplic().load_units()?,
            translations: self.samplic().load_translations()?,
        })
    }
}

impl StorableDevice for Device {
    type OmmuiStorableDevice = crate::ommui::filesystem::Device;
    type SamplicStorableDevice = crate::samplic::filesystem::Device;

    fn ommui_storable(&self) -> Self::OmmuiStorableDevice {
        crate::ommui::filesystem::Device::new(self.clone())
    }

    fn samplic_storable(&self) -> Self::SamplicStorableDevice {
        crate::samplic::filesystem::Device::new(self.clone())
    }
}

pub struct DeviceBuilder {
    override_system_path: Option<PathBuf>,
    override_base_config_path: Option<PathBuf>,
    override_base_data_path: Option<PathBuf>,
    override_base_cache_path: Option<PathBuf>,
    product_id: String,
    company_id: String,
}

fn default_system_path_for_company_id(company_id: &str) -> PathBuf {
    Path::new("/").join("etc").join(company_id).join("device")
}

impl DeviceBuilder {
    pub fn new(product_id: &str, company_id: &str) -> Self {
        DeviceBuilder {
            override_system_path: None,
            override_base_config_path: None,
            override_base_data_path: None,
            override_base_cache_path: None,
            product_id: product_id.to_string(),
            company_id: company_id.to_string(),
        }
    }

    pub fn base_system_path<P: AsRef<Path>>(mut self, p: P) -> Self {
        self.override_system_path = Some(p.as_ref().to_path_buf());
        self
    }

    pub fn base_config_path<P: AsRef<Path>>(mut self, p: P) -> Self {
        self.override_base_config_path = Some(p.as_ref().to_path_buf());
        self
    }

    pub fn base_data_path<P: AsRef<Path>>(mut self, p: P) -> Self {
        self.override_base_data_path = Some(p.as_ref().to_path_buf());
        self
    }

    pub fn build(self) -> Result<Device> {
        let DeviceBuilder {
            override_system_path,
            override_base_config_path,
            override_base_data_path,
            override_base_cache_path,
            product_id,
            company_id,
        } = self;

        let dirs =
            directories::ProjectDirs::from("at", &company_id, &product_id)
                .expect("Could not determine project directory");

        let system_path = override_system_path.unwrap_or_else(|| {
            default_system_path_for_company_id(&company_id)
        });

        let description =
            file_load_json::<crate::samplic::DeviceDescription, _>(
                system_path
                    .join("description")
                    .join("device")
                    .join("samplic")
                    .join("device.json"),
            )?;
        let device_id = description.uuid.to_hyphenated().to_string();
        let base_config_path = override_base_config_path
            .unwrap_or_else(|| dirs.config_dir().to_path_buf());
        let config_path = base_config_path.join(&device_id);

        let base_data_path = override_base_data_path
            .unwrap_or_else(|| dirs.data_dir().to_path_buf());
        let data_path = base_data_path.join(&device_id);

        let base_cache_path = override_base_cache_path
            .unwrap_or_else(|| dirs.cache_dir().to_path_buf());
        let cache_path = base_cache_path.join(&device_id);

        Ok(Device {
            system_path,
            config_path,
            data_path,
            cache_path,
            product_id,
        })
    }
}