signalk 0.7.0

A library to parse signalk maritime data
Documentation
use crate::definitions::V2NumberValue;
use crate::helper_functions::{get_f64_value, get_f64_value_for_path, F64CompatiblePath};
use crate::{SignalKGetError, V1CommonValueFields};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct V1Steering {
    pub rudder_angle: Option<V2NumberValue>,
    pub rudder_angle_target: Option<V2NumberValue>,
    pub autopilot: Option<V1SteeringAutopilot>,
}

impl F64CompatiblePath for V1Steering {
    fn get_f64_for_path(&self, path: &mut Vec<&str>) -> Result<f64, SignalKGetError> {
        match path[0] {
            "rudderAngle" => get_f64_value(&self.rudder_angle),
            "rudderAngleTarget" => get_f64_value(&self.rudder_angle_target),
            "autopilot" => get_f64_value_for_path(path, &self.autopilot),
            &_ => Err(SignalKGetError::NoSuchPath),
        }
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct V1SteeringAutopilot {
    pub state: Option<V1SteeringAutopilotState>,
    pub mode: Option<V1SteeringAutopilotMode>,
    pub target: Option<V1SteeringAutopilotTarget>,
    pub dead_zone: Option<V2NumberValue>,
    pub backlash: Option<V2NumberValue>,
    pub gain: Option<V2NumberValue>,
    pub max_drive_current: Option<V2NumberValue>,
    pub max_drive_rate: Option<V2NumberValue>,
    pub port_lock: Option<V2NumberValue>,
    pub starboard_lock: Option<V2NumberValue>,
}

impl F64CompatiblePath for V1SteeringAutopilot {
    fn get_f64_for_path(&self, path: &mut Vec<&str>) -> Result<f64, SignalKGetError> {
        match path[0] {
            &_ => Err(SignalKGetError::NoSuchPath),
        }
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(untagged)]
pub enum V1SteeringAutopilotState {
    Expanded(V1SteeringAutopilotStateExpandedValue),
    Value(V1SteeringAutopilotStateValue),
}

impl Default for V1SteeringAutopilotState {
    fn default() -> Self {
        V1SteeringAutopilotState::Value(V1SteeringAutopilotStateValue::default())
    }
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct V1SteeringAutopilotStateExpandedValue {
    pub value: Option<V1SteeringAutopilotStateValue>,
    #[serde(flatten)]
    pub common_value_fields: Option<V1CommonValueFields>,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub enum V1SteeringAutopilotStateValue {
    #[default]
    Auto,
    Standby,
    Alarm,
    NoDrift,
    Wind,
    DepthContour,
    Route,
    DirectControl,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(untagged)]
pub enum V1SteeringAutopilotMode {
    Expanded(V1SteeringAutopilotModeExpandedValue),
    Value(V1SteeringAutopilotModeValue),
}

impl Default for V1SteeringAutopilotMode {
    fn default() -> Self {
        V1SteeringAutopilotMode::Value(V1SteeringAutopilotModeValue::default())
    }
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct V1SteeringAutopilotModeExpandedValue {
    pub value: Option<V1SteeringAutopilotModeValue>,
    #[serde(flatten)]
    pub common_value_fields: Option<V1CommonValueFields>,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub enum V1SteeringAutopilotModeValue {
    #[default]
    PowerSave,
    Normal,
    Accurate,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct V1SteeringAutopilotTarget {
    pub wind_angle_apparent: Option<V2NumberValue>,
    pub wind_angle_true: Option<V2NumberValue>,
    pub heading_true: Option<V2NumberValue>,
    pub heading_magnetic: Option<V2NumberValue>,
}

impl F64CompatiblePath for V1SteeringAutopilotTarget {
    fn get_f64_for_path(&self, path: &mut Vec<&str>) -> Result<f64, SignalKGetError> {
        match path[0] {
            "windAngleApparent" => get_f64_value(&self.wind_angle_apparent),
            "windAngleTrue" => get_f64_value(&self.wind_angle_true),
            "headingTrue" => get_f64_value(&self.heading_true),
            "headingMagnetic" => get_f64_value(&self.heading_magnetic),
            &_ => Err(SignalKGetError::NoSuchPath),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::steering::{
        V1SteeringAutopilotState, V1SteeringAutopilotStateExpandedValue,
        V1SteeringAutopilotStateValue,
    };

    #[test]
    fn steering_autopilot_value() {
        let j = r#"{
        "value" : "auto",
        "$source": "foo.bar",
        "timestamp": "2014-08-15T19:00:15.402Z"
      }"#;
        println!("{:?}", j);
        let autopilot: V1SteeringAutopilotState = serde_json::from_str(j).unwrap();
        println!("{:?}", autopilot);
    }
    #[test]
    fn steering_autopilot_expanded_value() {
        let j = r#"{
        "value" : "auto",
        "$source": "foo.bar",
        "timestamp": "2014-08-15T19:00:15.402Z"
      }"#;
        println!("{:?}", j);
        let autopilot: V1SteeringAutopilotStateExpandedValue = serde_json::from_str(j).unwrap();
        println!("{:?}", autopilot);
    }
    #[test]
    fn steering_autopilot_state_value() {
        let j = r#" "auto" "#;
        println!("{:?}", j);
        let autopilot: V1SteeringAutopilotStateValue = serde_json::from_str(j).unwrap();
        println!("{:?}", autopilot);
    }
    #[test]
    fn serialization_of_stearing_value() {
        let j = V1SteeringAutopilotStateValue::Auto;
        println!("{:?}", j);
        let autopilot = serde_json::to_string(&j).unwrap();
        println!("{:?}", autopilot);
    }
}