Added config parsing and refactored parsing
This commit is contained in:
6 files changed
+538
-121
No files matched your search
+30
-49
@@ -3,75 +3,56 @@
|
||||
pub mod model;
|
||||
pub mod prelude;
|
||||
|
||||
use std::num::{ParseFloatError, ParseIntError};
|
||||
use std::str::ParseBoolError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DsnRespParseError {
|
||||
AttrMissing(String),
|
||||
ParseIntErr(ParseIntError),
|
||||
ParseFloatErr(ParseFloatError),
|
||||
ParseBoolErr(ParseBoolError),
|
||||
#[error("Failed to read XML: {0}")]
|
||||
XMLReaderError(xml::reader::Error),
|
||||
#[error("Failed to parse element '{element}': {err}")]
|
||||
ElementParsingError { element: String, err: DsnFieldError },
|
||||
}
|
||||
|
||||
impl From<ParseIntError> for DsnRespParseError {
|
||||
fn from(error: ParseIntError) -> Self {
|
||||
DsnRespParseError::ParseIntErr(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseFloatError> for DsnRespParseError {
|
||||
fn from(error: ParseFloatError) -> Self {
|
||||
DsnRespParseError::ParseFloatErr(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseBoolError> for DsnRespParseError {
|
||||
fn from(error: ParseBoolError) -> Self {
|
||||
DsnRespParseError::ParseBoolErr(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<xml::reader::Error> for DsnRespParseError {
|
||||
fn from(error: xml::reader::Error) -> Self {
|
||||
DsnRespParseError::XMLReaderError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DsnRespParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
DsnRespParseError::AttrMissing(attr) => write!(f, "Attr missing: {}", attr),
|
||||
DsnRespParseError::ParseIntErr(e) => write!(f, "Int parse error: {}", e),
|
||||
DsnRespParseError::ParseFloatErr(e) => write!(f, "Int parse error: {}", e),
|
||||
DsnRespParseError::ParseBoolErr(e) => write!(f, "Bool parse error: {}", e),
|
||||
DsnRespParseError::XMLReaderError(e) => write!(f, "XML Parse error: {}", e),
|
||||
}
|
||||
}
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DsnFieldError {
|
||||
#[error("Attribute '{0}' is missing")]
|
||||
AttrMissing(String),
|
||||
#[error("Failed to parse attribute '{attribute}': {err}")]
|
||||
AttributeParseFailed { err: String, attribute: String },
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::model::DsnResponse;
|
||||
use crate::DsnRespParseError;
|
||||
use crate::model::config::DsnConfig;
|
||||
use crate::model::status::DsnStatus;
|
||||
use crate::prelude::DsnModel;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
|
||||
fn parse_test_file() -> DsnResponse {
|
||||
fn parse_test_file() -> Result<DsnStatus, DsnRespParseError> {
|
||||
let example_file = File::open("data/dsn.xml").unwrap();
|
||||
let buf_reader = BufReader::new(example_file);
|
||||
DsnResponse::from_xml_response(buf_reader).unwrap()
|
||||
DsnStatus::from_xml_response(buf_reader)
|
||||
}
|
||||
|
||||
fn parse_cfg_file() -> Result<DsnConfig, DsnRespParseError> {
|
||||
let example_file = File::open("data/config.xml").unwrap();
|
||||
let buf_reader = BufReader::new(example_file);
|
||||
DsnConfig::from_xml_response(buf_reader)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse() {
|
||||
let response = parse_test_file();
|
||||
println!("{:?}", response.stations)
|
||||
let response = parse_test_file().unwrap();
|
||||
|
||||
assert_eq!(response.stations.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_active_targets() {
|
||||
let response = parse_test_file();
|
||||
println!("{:?}", response.get_active_targets());
|
||||
fn test_parse_config() {
|
||||
let config = parse_cfg_file().unwrap();
|
||||
assert_eq!(config.sites.len(), 3);
|
||||
assert_eq!(config.spacecraft_map.len(), 168)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
use crate::model::{DsnField, DsnModel};
|
||||
use crate::{DsnFieldError, DsnRespParseError};
|
||||
use std::collections::HashMap;
|
||||
use std::io::{BufReader, Read};
|
||||
use xml::EventReader;
|
||||
use xml::attribute::OwnedAttribute;
|
||||
use xml::reader::XmlEvent;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DsnConfig {
|
||||
pub sites: Vec<SiteCfg>,
|
||||
pub spacecraft_map: HashMap<String, SpacecraftMap>,
|
||||
}
|
||||
|
||||
impl DsnModel for DsnConfig {
|
||||
fn from_xml_response<T>(reader: BufReader<T>) -> Result<Self, DsnRespParseError>
|
||||
where
|
||||
T: Read,
|
||||
{
|
||||
let mut sites = Vec::new();
|
||||
let mut site_cfg: Option<SiteCfg> = None;
|
||||
|
||||
let mut spacecraft_map = HashMap::new();
|
||||
let mut spacecraft_cfg: Option<SpacecraftMap> = None;
|
||||
|
||||
let parser = EventReader::new(reader).into_iter();
|
||||
for e in parser {
|
||||
match e {
|
||||
Ok(XmlEvent::StartElement {
|
||||
name, attributes, ..
|
||||
}) => {
|
||||
if name.local_name == "site" {
|
||||
site_cfg = Some(SiteCfg::parse_field(&attributes).map_err(|err| {
|
||||
DsnRespParseError::ElementParsingError {
|
||||
element: "site".to_string(),
|
||||
err,
|
||||
}
|
||||
})?)
|
||||
} else if let Some(site_cfg) = &mut site_cfg
|
||||
&& name.local_name == "dish"
|
||||
{
|
||||
site_cfg.add_dish(DishCfg::parse_field(&attributes).map_err(|err| {
|
||||
DsnRespParseError::ElementParsingError {
|
||||
err,
|
||||
element: "dish".to_string(),
|
||||
}
|
||||
})?)
|
||||
} else if name.local_name == "spacecraft" {
|
||||
spacecraft_cfg =
|
||||
Some(SpacecraftMap::parse_field(&attributes).map_err(|err| {
|
||||
DsnRespParseError::ElementParsingError {
|
||||
err,
|
||||
element: "spacecraft".to_string(),
|
||||
}
|
||||
})?);
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndElement { name }) => {
|
||||
if name.local_name == "site" {
|
||||
if let Some(site_cfg) = &site_cfg {
|
||||
sites.push(site_cfg.clone());
|
||||
}
|
||||
site_cfg = None;
|
||||
} else if name.local_name == "spacecraft" {
|
||||
if let Some(spacecraft_cfg) = &spacecraft_cfg {
|
||||
spacecraft_map
|
||||
.insert(spacecraft_cfg.name.clone(), spacecraft_cfg.clone());
|
||||
}
|
||||
spacecraft_cfg = None;
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndDocument) => {}
|
||||
Err(e) => {
|
||||
return Err(DsnRespParseError::XMLReaderError(e));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
sites,
|
||||
spacecraft_map,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SiteCfg {
|
||||
pub name: String,
|
||||
pub friendly_name: String,
|
||||
pub longitude: f32,
|
||||
pub latitude: f32,
|
||||
pub dishes: Vec<DishCfg>,
|
||||
}
|
||||
|
||||
impl SiteCfg {
|
||||
pub fn add_dish(&mut self, dish: DishCfg) {
|
||||
self.dishes.push(dish);
|
||||
}
|
||||
}
|
||||
|
||||
impl DsnField for SiteCfg {
|
||||
fn parse_field(attrs: &[OwnedAttribute]) -> Result<Self, DsnFieldError> {
|
||||
let name = Self::get_attr(attrs, "name")?;
|
||||
let friendly_name = Self::get_attr(attrs, "friendlyName")?;
|
||||
let longitude = Self::parse_attribute::<f32>(attrs, "longitude")?;
|
||||
let latitude = Self::parse_attribute::<f32>(attrs, "latitude")?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
friendly_name,
|
||||
longitude,
|
||||
latitude,
|
||||
dishes: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DishCfg {
|
||||
pub name: String,
|
||||
pub friendly_name: String,
|
||||
pub dish_type: String,
|
||||
}
|
||||
|
||||
impl DsnField for DishCfg {
|
||||
fn parse_field(attrs: &[OwnedAttribute]) -> Result<Self, DsnFieldError> {
|
||||
let name = Self::get_attr(attrs, "name")?;
|
||||
let friendly_name = Self::get_attr(attrs, "friendlyName")?;
|
||||
let dish_type = Self::get_attr(attrs, "type")?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
friendly_name,
|
||||
dish_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SpacecraftMap {
|
||||
pub name: String,
|
||||
pub explorer_name: String,
|
||||
pub friendly_name: String,
|
||||
pub thumbnail: Option<bool>,
|
||||
}
|
||||
|
||||
impl DsnField for SpacecraftMap {
|
||||
fn parse_field(attrs: &[OwnedAttribute]) -> Result<Self, DsnFieldError> {
|
||||
let name = Self::get_attr(attrs, "name")?;
|
||||
let explorer_name = Self::get_attr(attrs, "explorerName")?;
|
||||
let friendly_name = Self::get_attr(attrs, "friendlyName")?;
|
||||
let thumbnail = Self::parse_optional_attribute::<bool>(attrs, "thumbnail")?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
explorer_name,
|
||||
friendly_name,
|
||||
thumbnail,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
pub mod config;
|
||||
pub mod status;
|
||||
|
||||
use crate::{DsnFieldError, DsnRespParseError};
|
||||
use std::fmt::Debug;
|
||||
use std::io::BufReader;
|
||||
use std::str::FromStr;
|
||||
use xml::attribute::OwnedAttribute;
|
||||
pub trait DsnModel: Sized {
|
||||
fn from_xml_string(resp_str: &str) -> Result<Self, DsnRespParseError> {
|
||||
Self::from_xml_response(BufReader::new(resp_str.as_bytes()))
|
||||
}
|
||||
|
||||
fn from_xml_response<T>(reader: BufReader<T>) -> Result<Self, DsnRespParseError>
|
||||
where
|
||||
T: std::io::Read;
|
||||
}
|
||||
|
||||
pub trait DsnField: Sized + Clone {
|
||||
fn get_attr(attrs: &[OwnedAttribute], name: &str) -> Result<String, DsnFieldError> {
|
||||
attrs
|
||||
.iter()
|
||||
.find_map(|o| {
|
||||
if o.name.local_name.eq(name) {
|
||||
Some(o.value.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| DsnFieldError::AttrMissing(name.to_string()))
|
||||
}
|
||||
|
||||
fn parse<T: FromStr>(name: &str, value: &str) -> Result<T, DsnFieldError>
|
||||
where
|
||||
<T as FromStr>::Err: Debug,
|
||||
{
|
||||
value
|
||||
.parse::<T>()
|
||||
.map_err(|err| DsnFieldError::AttributeParseFailed {
|
||||
err: format!("{err:?}"),
|
||||
attribute: name.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_attribute<T: FromStr>(attrs: &[OwnedAttribute], name: &str) -> Result<T, DsnFieldError>
|
||||
where
|
||||
<T as FromStr>::Err: Debug,
|
||||
{
|
||||
Self::parse::<T>(name, &Self::get_attr(attrs, name)?)
|
||||
}
|
||||
|
||||
fn parse_optional_attribute<T: FromStr>(
|
||||
attrs: &[OwnedAttribute],
|
||||
name: &str,
|
||||
) -> Result<Option<T>, DsnFieldError>
|
||||
where
|
||||
<T as FromStr>::Err: Debug,
|
||||
{
|
||||
let attr = if let Ok(attr) = Self::get_attr(attrs, name)
|
||||
&& !attr.is_empty()
|
||||
{
|
||||
Some(Self::parse::<T>(name, &attr)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(attr)
|
||||
}
|
||||
|
||||
fn parse_field(attrs: &[OwnedAttribute]) -> Result<Self, DsnFieldError>;
|
||||
}
|
||||
@@ -1,30 +1,16 @@
|
||||
use std::convert::TryFrom;
|
||||
use crate::model::{DsnField, DsnModel};
|
||||
use crate::{DsnFieldError, DsnRespParseError};
|
||||
use std::io::BufReader;
|
||||
|
||||
use crate::DsnRespParseError;
|
||||
use xml::EventReader;
|
||||
use xml::attribute::OwnedAttribute;
|
||||
use xml::reader::XmlEvent;
|
||||
|
||||
fn get_attr(attrs: &[OwnedAttribute], name: &str) -> Result<String, DsnRespParseError> {
|
||||
attrs
|
||||
.iter()
|
||||
.find_map(|o| {
|
||||
if o.name.local_name.eq(name) {
|
||||
Some(o.value.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| DsnRespParseError::AttrMissing(name.to_string()))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DsnResponse {
|
||||
pub struct DsnStatus {
|
||||
pub stations: Vec<Station>,
|
||||
}
|
||||
|
||||
impl DsnResponse {
|
||||
impl DsnStatus {
|
||||
pub fn get_active_targets(&self) -> Vec<Target> {
|
||||
let mut targets = Vec::new();
|
||||
|
||||
@@ -36,12 +22,10 @@ impl DsnResponse {
|
||||
|
||||
targets
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_xml_string(resp_str: &str) -> Result<DsnResponse, DsnRespParseError> {
|
||||
Self::from_xml_response(BufReader::new(resp_str.as_bytes()))
|
||||
}
|
||||
|
||||
pub fn from_xml_response<T>(reader: BufReader<T>) -> Result<DsnResponse, DsnRespParseError>
|
||||
impl DsnModel for DsnStatus {
|
||||
fn from_xml_response<T>(reader: BufReader<T>) -> Result<DsnStatus, DsnRespParseError>
|
||||
where
|
||||
T: std::io::Read,
|
||||
{
|
||||
@@ -60,15 +44,46 @@ impl DsnResponse {
|
||||
if let Some(station) = station {
|
||||
stations.push(station);
|
||||
}
|
||||
station = Some(Station::try_from(attributes)?);
|
||||
station = Some(Station::parse_field(&attributes).map_err(|err| {
|
||||
DsnRespParseError::ElementParsingError {
|
||||
err,
|
||||
element: "station".to_string(),
|
||||
}
|
||||
})?);
|
||||
} else if name.local_name.contains("dish") {
|
||||
dish = Some(Dish::try_from(attributes)?);
|
||||
dish = Some(Dish::parse_field(&attributes).map_err(|err| {
|
||||
DsnRespParseError::ElementParsingError {
|
||||
err,
|
||||
element: "dish".to_string(),
|
||||
}
|
||||
})?);
|
||||
} else if name.local_name.contains("downSignal") {
|
||||
dish = Some(dish.unwrap().add_down_signal(Signal::try_from(attributes)?));
|
||||
dish = Some(dish.unwrap().add_down_signal(
|
||||
Signal::parse_field(&attributes).map_err(|err| {
|
||||
DsnRespParseError::ElementParsingError {
|
||||
err,
|
||||
element: "downSignal".to_string(),
|
||||
}
|
||||
})?,
|
||||
));
|
||||
} else if name.local_name.contains("upSignal") {
|
||||
dish = Some(dish.unwrap().add_up_signal(Signal::try_from(attributes)?));
|
||||
dish = Some(dish.unwrap().add_up_signal(
|
||||
Signal::parse_field(&attributes).map_err(|err| {
|
||||
DsnRespParseError::ElementParsingError {
|
||||
err,
|
||||
element: "upSignal".to_string(),
|
||||
}
|
||||
})?,
|
||||
));
|
||||
} else if name.local_name.contains("target") {
|
||||
dish = Some(dish.unwrap().add_target(Target::try_from(attributes)?));
|
||||
dish = Some(dish.unwrap().add_target(
|
||||
Target::parse_field(&attributes).map_err(|err| {
|
||||
DsnRespParseError::ElementParsingError {
|
||||
err,
|
||||
element: "target".to_string(),
|
||||
}
|
||||
})?,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::EndElement { name }) => {
|
||||
@@ -84,13 +99,13 @@ impl DsnResponse {
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(DsnRespParseError::from(e));
|
||||
return Err(DsnRespParseError::XMLReaderError(e));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(DsnResponse { stations })
|
||||
Ok(DsnStatus { stations })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,14 +125,12 @@ impl Station {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<OwnedAttribute>> for Station {
|
||||
type Error = DsnRespParseError;
|
||||
|
||||
fn try_from(attrs: Vec<OwnedAttribute>) -> Result<Self, Self::Error> {
|
||||
let name = get_attr(&attrs, "name")?;
|
||||
let friendly_name = get_attr(&attrs, "friendlyName")?;
|
||||
let time_utc = get_attr(&attrs, "timeUTC")?.parse::<u64>()?;
|
||||
let tz_offset = get_attr(&attrs, "timeZoneOffset")?.parse::<f64>()?;
|
||||
impl DsnField for Station {
|
||||
fn parse_field(attrs: &[OwnedAttribute]) -> Result<Self, DsnFieldError> {
|
||||
let name = Self::get_attr(attrs, "name")?;
|
||||
let friendly_name = Self::get_attr(attrs, "friendlyName")?;
|
||||
let time_utc = Self::parse_attribute::<u64>(attrs, "timeUTC")?;
|
||||
let tz_offset = Self::parse_attribute::<f64>(attrs, "timeZoneOffset")?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
@@ -135,7 +148,7 @@ pub enum SignalType {
|
||||
Carrier,
|
||||
#[default]
|
||||
None,
|
||||
Unkown(String),
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
impl From<String> for SignalType {
|
||||
@@ -144,7 +157,7 @@ impl From<String> for SignalType {
|
||||
"data" => SignalType::Data,
|
||||
"carrier" => SignalType::Carrier,
|
||||
"none" => SignalType::None,
|
||||
_ => SignalType::Unkown(s),
|
||||
_ => SignalType::Unknown(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,16 +172,14 @@ pub struct Signal {
|
||||
pub spacecraft_id: Option<i32>,
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<OwnedAttribute>> for Signal {
|
||||
type Error = DsnRespParseError;
|
||||
|
||||
fn try_from(attrs: Vec<OwnedAttribute>) -> Result<Self, Self::Error> {
|
||||
let signal_type = SignalType::from(get_attr(&attrs, "signalType")?);
|
||||
let data_rate = get_attr(&attrs, "dataRate")?.parse::<f64>().ok();
|
||||
let frequency = get_attr(&attrs, "frequency")?.parse::<f64>().ok();
|
||||
let power = get_attr(&attrs, "power")?.parse::<f64>().ok();
|
||||
let spacecraft = get_attr(&attrs, "spacecraft")?;
|
||||
let spacecraft_id = get_attr(&attrs, "spacecraftID")?.parse::<i32>().ok();
|
||||
impl DsnField for Signal {
|
||||
fn parse_field(attrs: &[OwnedAttribute]) -> Result<Self, DsnFieldError> {
|
||||
let signal_type = SignalType::from(Self::get_attr(attrs, "signalType")?);
|
||||
let data_rate = Self::parse_optional_attribute::<f64>(attrs, "dataRate")?;
|
||||
let frequency = Self::parse_optional_attribute::<f64>(attrs, "frequency")?;
|
||||
let power = Self::parse_optional_attribute::<f64>(attrs, "power")?;
|
||||
let spacecraft = Self::get_attr(attrs, "spacecraft")?;
|
||||
let spacecraft_id = Self::parse_optional_attribute::<i32>(attrs, "spacecraftID")?;
|
||||
|
||||
Ok(Self {
|
||||
signal_type,
|
||||
@@ -193,15 +204,13 @@ pub struct Target {
|
||||
pub rtlt: f64,
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<OwnedAttribute>> for Target {
|
||||
type Error = DsnRespParseError;
|
||||
|
||||
fn try_from(attrs: Vec<OwnedAttribute>) -> Result<Self, Self::Error> {
|
||||
let name = get_attr(&attrs, "name")?;
|
||||
let id = get_attr(&attrs, "id")?.parse::<u32>()?;
|
||||
let upleg_range = get_attr(&attrs, "uplegRange")?.parse::<f64>()?;
|
||||
let downleg_range = get_attr(&attrs, "downlegRange")?.parse::<f64>()?;
|
||||
let rtlt = get_attr(&attrs, "rtlt")?.parse::<f64>()?;
|
||||
impl DsnField for Target {
|
||||
fn parse_field(attrs: &[OwnedAttribute]) -> Result<Self, DsnFieldError> {
|
||||
let name = Self::get_attr(attrs, "name")?;
|
||||
let id = Self::parse_attribute::<u32>(attrs, "id")?;
|
||||
let upleg_range = Self::parse_attribute::<f64>(attrs, "uplegRange")?;
|
||||
let downleg_range = Self::parse_attribute::<f64>(attrs, "downlegRange")?;
|
||||
let rtlt = Self::parse_attribute::<f64>(attrs, "rtlt")?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
@@ -244,17 +253,15 @@ impl Dish {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<OwnedAttribute>> for Dish {
|
||||
type Error = DsnRespParseError;
|
||||
|
||||
fn try_from(attrs: Vec<OwnedAttribute>) -> Result<Self, Self::Error> {
|
||||
let name = get_attr(&attrs, "name")?;
|
||||
let azimuth_angle = get_attr(&attrs, "azimuthAngle")?.parse::<f64>().ok();
|
||||
let elevation_angle = get_attr(&attrs, "elevationAngle")?.parse::<f64>().ok();
|
||||
let wind_speed = get_attr(&attrs, "windSpeed")?.parse::<f64>().ok();
|
||||
let is_mspa = get_attr(&attrs, "isMSPA")?.parse::<bool>()?;
|
||||
let is_array = get_attr(&attrs, "isArray")?.parse::<bool>()?;
|
||||
let is_ddor = get_attr(&attrs, "isDDOR")?.parse::<bool>()?;
|
||||
impl DsnField for Dish {
|
||||
fn parse_field(attrs: &[OwnedAttribute]) -> Result<Self, DsnFieldError> {
|
||||
let name = Self::get_attr(attrs, "name")?;
|
||||
let azimuth_angle = Self::parse_optional_attribute::<f64>(attrs, "azimuthAngle")?;
|
||||
let elevation_angle = Self::parse_optional_attribute::<f64>(attrs, "elevationAngle")?;
|
||||
let wind_speed = Self::parse_optional_attribute::<f64>(attrs, "windSpeed")?;
|
||||
let is_mspa = Self::parse_attribute::<bool>(attrs, "isMSPA")?;
|
||||
let is_array = Self::parse_attribute::<bool>(attrs, "isArray")?;
|
||||
let is_ddor = Self::parse_attribute::<bool>(attrs, "isDDOR")?;
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
Reference in new issue
Block a user