indi 5.1.1

Client library for interfacing with the Instrument Neutral Distributed Interface (INDI) protocol.
Documentation
use std::{collections::HashMap, ops::Deref};

use crate::{serialization::OneNumber, Number, Parameter};
use twinkle_client::notify::NotifyArc;

use crate::telescope::parameter_with_config::{
    ActiveParameterWithConfig, FromParam, IntoValue, ParameterWithConfig,
};

use super::DeviceError;

#[derive(derive_more::Deref, derive_more::Into, derive_more::From)]
pub struct BinningParameter(ActiveParameterWithConfig<BinningConfig>);

#[derive(Clone, Copy)]
pub struct Binning {
    pub hor: u8,
    pub ver: u8,
}

#[derive(Clone)]
pub struct BinningConfig {
    parameter: &'static str,
    hor: &'static str,
    ver: &'static str,
}

impl BinningConfig {
    pub(super) fn new(parameter: &'static str, hor: &'static str, ver: &'static str) -> Self {
        BinningConfig {
            parameter,
            hor,
            ver,
        }
    }
}

impl IntoValue for BinningConfig {
    type Value = Vec<OneNumber>;
    type SingleValue = Binning;

    fn into_value<T: Into<Self::SingleValue>>(&self, value: T) -> Self::Value {
        let single_value = value.into();
        vec![
            OneNumber {
                name: self.ver.to_string(),
                value: single_value.ver.into(),
            },
            OneNumber {
                name: self.hor.to_string(),
                value: single_value.hor.into(),
            },
        ]
    }
}

impl FromParam for BinningConfig {
    type Value = Binning;
    type Error = DeviceError;

    fn new(param: NotifyArc<Parameter>, config: Self) -> ParameterWithConfig<Self> {
        ParameterWithConfig {
            parameter: param,
            config,
        }
    }
    fn from_parameter<T: Deref<Target = Parameter>>(
        &self,
        param: &T,
    ) -> Result<Self::Value, Self::Error>
    where
        Self: Sized,
    {
        let values = param.deref().get_values::<HashMap<String, Number>>()?;
        let hor: f64 = values
            .get(self.hor)
            .ok_or(DeviceError::Missing)?
            .value
            .into();
        let ver: f64 = values
            .get(self.ver)
            .ok_or(DeviceError::Missing)?
            .value
            .into();
        Ok(Binning {
            hor: hor as u8,
            ver: ver as u8,
        })
    }

    fn get_parameter_name(&self) -> &'static str {
        self.parameter
    }
}