e173 0.1.0-alpha.7

A library implementing various aspects of the ESTA BSR E1.73 standard
Documentation
mod dmx;

use std::collections::HashMap;

use crate::schema::{DeviceClass, EstaDmx, Parameter};
use crate::{e173_types, Error};

pub use dmx::{DmxDriver, ParamRange, ParameterCombo, ParameterConstraint};

e173_types! {

#[serde(rename_all = "camelCase")]
pub struct ParameterDatabase {
    pub parameters: HashMap<String, Parameter>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub dmx_driver: Option<DmxDriver>,
}

}

pub fn create_parameter_database(device_class: &DeviceClass) -> Result<ParameterDatabase, Error> {
    let parameters = device_class.parameters.clone();

    let dmx = get_dmx_serializer(device_class)?;
    let dmx_driver = match dmx {
        Some(dmx) => {
            let driver = DmxDriver::from(&dmx)?;
            if driver.chunks.is_empty() && driver.clusters.is_empty() {
                None
            } else {
                Some(driver)
            }
        }
        None => None,
    };

    Ok(ParameterDatabase {
        parameters,
        dmx_driver,
    })
}

fn get_dmx_serializer(device_class: &DeviceClass) -> Result<Option<EstaDmx>, Error> {
    let mut ser_iter = device_class.serializers.iter().filter(|(_, ser)| {
        matches!(ser.library.as_deref(), Some("org.esta.lib.core")) && ser.class == "esta-dmx"
    });

    let Some(serializer) = ser_iter.next().map(|(_, ser)| ser) else {
        return Ok(None);
    };

    // TODO: Updates to the standard to make this error condition unnecessary.
    if let Some((key, _)) = ser_iter.next() {
        return Err(Error::invalid_device_class(
            "Device class contains multiple ESTA DMX serializers",
            format!("/serializers/{key}"),
        ));
    }

    let Some(default_val) = &serializer.default else {
        return Ok(None);
    };

    serde_json::from_value(default_val.clone())
        .map(Some)
        .map_err(Error::dmx_parse)
}