pub mod deprecated {
use crate::parser::errors::XmlParseError;
use crate::protocol::{Deprecated, DeprecatedSince};
#[derive(Debug, Clone)]
pub struct XmlDeprecated {
pub since: String,
pub replaced_by: String,
}
impl XmlDeprecated {
pub fn to_deprecated(&self) -> Result<Deprecated, XmlParseError> {
let mut since_parts = self.since.split('-');
let year: i32 = since_parts
.next()
.ok_or(XmlParseError::InvalidDeprecatedSinceDateFormat(
self.since.clone(),
))?
.parse()
.map_err(XmlParseError::InvalidDeprecatedSinceYear)?;
let month: u8 = since_parts
.next()
.ok_or(XmlParseError::InvalidDeprecatedSinceDateFormat(
self.since.clone(),
))?
.parse()
.map_err(XmlParseError::InvalidDeprecatedSinceMonth)?;
Ok(Deprecated::new(
DeprecatedSince::new(year, month),
self.replaced_by.to_string(),
))
}
}
#[test]
fn correct_deprecated_since_date_parsing() {
let deprecated = XmlDeprecated {
since: "2023-10".to_string(),
replaced_by: "something".to_string(),
}
.to_deprecated()
.unwrap();
assert_eq!(deprecated.since().year(), 2023);
assert_eq!(deprecated.since().month(), 10);
}
}
pub mod enums {
use std::collections::HashMap;
use crate::parser::errors::XmlParseError;
use crate::protocol::{
Enum, EnumEntry, EnumEntryMavCmdFlags, EnumEntryMavCmdParam, Units, Value,
};
use super::deprecated::XmlDeprecated;
#[derive(Debug, Clone)]
pub struct XmlEnumEntry {
pub value: String,
pub name: String,
pub description: String,
pub cmd_flags: XmlEnumEntryMavCmdFlags,
pub params: Vec<XmlEnumEntryMavCmdParam>,
pub deprecated: Option<XmlDeprecated>,
pub wip: bool,
pub defined_in: Option<String>,
}
impl XmlEnumEntry {
pub fn to_enum_entry(&self) -> Result<EnumEntry, XmlParseError> {
let mut params = Vec::new();
for param in &self.params {
params.push(param.to_enum_entry_mav_cmd_param()?);
}
Ok(EnumEntry::new(
self.value
.parse::<u32>()
.map_err(XmlParseError::EnumEntryValueParseFailed)?,
self.name.to_string(),
self.description.to_string(),
self.cmd_flags.to_enum_entry_mav_cmd_flags()?,
params,
self.wip,
match &self.deprecated {
Some(deprecated) => Some(deprecated.to_deprecated()?),
None => None,
},
self.defined_in.clone(),
))
}
}
#[derive(Debug, Clone)]
pub struct XmlEnum {
pub name: String,
pub bitmask: bool,
pub description: String,
pub entries: HashMap<String, XmlEnumEntry>,
pub deprecated: Option<XmlDeprecated>,
pub defined_in: Vec<String>,
}
impl XmlEnum {
pub fn to_enum(&self) -> Result<Enum, XmlParseError> {
let mut entries = HashMap::new();
for (name, entry) in &self.entries {
entries.insert(name.clone(), entry.to_enum_entry()?);
}
Ok(Enum::new(
self.name.to_string(),
self.description.to_string(),
entries,
self.bitmask,
match &self.deprecated {
None => None,
Some(deprecated) => Some(deprecated.to_deprecated()?),
},
self.defined_in.clone(),
))
}
}
#[derive(Debug, Clone)]
pub struct XmlEnumEntryMavCmdFlags {
pub has_location: Option<bool>,
pub is_destination: Option<bool>,
pub mission_only: Option<bool>,
}
impl XmlEnumEntryMavCmdFlags {
pub fn to_enum_entry_mav_cmd_flags(
&self,
) -> Result<Option<EnumEntryMavCmdFlags>, XmlParseError> {
let has_location = match &self.has_location {
Some(true) => Some(true),
_ => None,
};
let is_destination = match &self.is_destination {
Some(true) => Some(true),
_ => None,
};
let mission_only = match &self.mission_only {
Some(true) => Some(true),
_ => None,
};
Ok(match (has_location, is_destination, mission_only) {
(None, None, None) => None,
_ => Some(EnumEntryMavCmdFlags::new(
has_location,
is_destination,
mission_only,
)),
})
}
}
#[derive(Debug, Clone)]
pub struct XmlEnumEntryMavCmdParam {
pub index: String,
pub description: String,
pub label: Option<String>,
pub units: Option<String>,
pub r#enum: Option<String>,
pub decimal_places: Option<String>,
pub increment: Option<String>,
pub min_value: Option<String>,
pub max_value: Option<String>,
pub reserved: Option<String>,
pub default: Option<String>,
}
impl XmlEnumEntryMavCmdParam {
pub fn to_enum_entry_mav_cmd_param(&self) -> Result<EnumEntryMavCmdParam, XmlParseError> {
let index = self
.index
.parse::<u8>()
.map_err(XmlParseError::EnumEntryMavCmdParamInvalidIndex)?;
let units = match &self.units {
None => None,
Some(units) => Units::parse(units).map_err(XmlParseError::UnitsError)?,
};
let decimal_places = match &self.decimal_places {
None => None,
Some(dec) => Some(
dec.parse::<u8>()
.map_err(XmlParseError::EnumEntryMavCmdParamInvalidDecimalPlaces)?,
),
};
let increment = match &self.increment {
None => None,
Some(inc) => Some(
Value::parse(inc)
.map_err(XmlParseError::EnumEntryMavCmdParamInvalidIncrement)?,
),
};
let min_value = match &self.min_value {
None => None,
Some(min) => Some(
Value::parse(min)
.map_err(XmlParseError::EnumEntryMavCmdParamInvalidMinValue)?,
),
};
let max_value = match &self.max_value {
None => None,
Some(max) => Some(
Value::parse(max)
.map_err(XmlParseError::EnumEntryMavCmdParamInvalidMaxValue)?,
),
};
let reserved = match &self.reserved {
None => false,
Some(reserved) => reserved
.parse::<bool>()
.map_err(XmlParseError::EnumEntryMavCmdParamInvalidReserved)?,
};
let default = match &self.default {
None => None,
Some(def) => Some(
Value::parse(def)
.map_err(XmlParseError::EnumEntryMavCmdParamInvalidDefaultValue)?,
),
};
Ok(EnumEntryMavCmdParam::new(
index,
self.description.clone(),
self.label.clone(),
units,
self.r#enum.clone(),
decimal_places,
increment,
min_value,
max_value,
reserved,
default,
))
}
}
}
pub mod messages {
use super::deprecated::XmlDeprecated;
use crate::parser::errors::XmlParseError;
use crate::protocol::{
Message, MessageField, MessageFieldInvalidValue, MessageFieldType, MessageId, Units, Value,
};
#[derive(Debug, Clone)]
pub struct XmlMessageField {
pub field_type: String,
pub name: String,
pub description: String,
pub r#enum: Option<String>,
pub units: Option<String>,
pub bitmask: bool,
pub print_format: Option<String>,
pub default: Option<String>,
pub invalid: Option<String>,
pub instance: bool,
pub extension: bool,
}
impl XmlMessageField {
pub fn to_message_field(&self) -> Result<MessageField, XmlParseError> {
let r#type = MessageFieldType::parse(self.field_type.as_str())
.map_err(XmlParseError::InvalidMessageField)?;
let units = match &self.units {
None => None,
Some(units) => Units::parse(units.as_str()).map_err(XmlParseError::UnitsError)?,
};
let default = match &self.default {
None => None,
Some(default) => Some(Value::parse(default).map_err(XmlParseError::InvalidValue)?),
};
let invalid = match self.invalid.clone() {
Some(invalid) => Some(
MessageFieldInvalidValue::parse(invalid.as_str())
.map_err(XmlParseError::InvalidMessageField)?,
),
None => None,
};
Ok(MessageField::new(
self.name.to_string(),
self.description.to_string(),
r#type,
self.r#enum.clone(),
units,
self.bitmask,
self.print_format.clone(),
default,
invalid,
self.instance,
self.extension,
))
}
}
#[derive(Debug, Clone)]
pub struct XmlMessage {
pub id: String,
pub name: String,
pub description: String,
pub fields: Vec<XmlMessageField>,
pub wip: bool,
pub deprecated: Option<XmlDeprecated>,
pub defined_in: Option<String>,
}
impl XmlMessage {
pub fn to_message(&self) -> Result<Message, XmlParseError> {
let mut fields: Vec<MessageField> = Vec::new();
for xml_fld in &self.fields {
fields.push(xml_fld.to_message_field()?);
}
Ok(Message::new(
self.id
.parse::<MessageId>()
.map_err(XmlParseError::InvalidMessageId)?,
self.name.to_string(),
self.description.to_string(),
fields,
self.wip,
match &self.deprecated {
Some(deprecated) => Some(deprecated.to_deprecated()?),
None => None,
},
self.defined_in.clone(),
))
}
}
}