use crate::{error, Result};
use indexmap::{IndexMap, IndexSet};
use snafu::ResultExt;
use xio_base_datatypes::{DataType, DataValue, DataValueDescriptive};
use xio_jobset::{
ChannelAssignment, Job, JobSet, Metadata, ParameterDescription,
ParameterSet, ParameterSetMetadata,
};
pub trait LoadableDevice {
fn load_device_parameter_metadata(
&self,
) -> Result<ParameterSetMetadata>;
fn load_device_parameter_descriptions(
&self,
) -> Result<IndexMap<String, ParameterDescription>>;
fn load_device_parameter_values(
&self,
) -> Result<IndexMap<String, DataValueDescriptive>>;
fn load_device_parameterset(&self) -> Result<ParameterSet> {
let metadata = self.load_device_parameter_metadata()?;
let descriptions = self.load_device_parameter_descriptions()?;
let values = self.load_device_parameter_values()?;
Ok(ParameterSet {
metadata,
descriptions,
values,
})
}
fn load_board_index(&self) -> Result<IndexSet<String>>;
fn load_board_mapping(
&self,
board_id: &str,
) -> Result<IndexMap<String, ChannelAssignment>>;
fn load_board_parameter_metadata(
&self,
board_id: &str,
) -> Result<ParameterSetMetadata>;
fn load_board_parameter_descriptions(
&self,
board_id: &str,
) -> Result<IndexMap<String, ParameterDescription>>;
fn load_board_parameter_values(
&self,
board_id: &str,
) -> Result<IndexMap<String, DataValueDescriptive>>;
fn load_board_parameterset(
&self,
board_id: &str,
) -> Result<ParameterSet> {
let metadata = self.load_board_parameter_metadata(board_id)?;
let descriptions =
self.load_board_parameter_descriptions(board_id)?;
let values = self.load_board_parameter_values(board_id)?;
Ok(ParameterSet {
metadata,
descriptions,
values,
})
}
fn load_calibration_parameter_metadata(
&self,
calibration_id: &str,
) -> Result<ParameterSetMetadata>;
fn load_calibration_parameter_descriptions(
&self,
calibration_id: &str,
) -> Result<IndexMap<String, ParameterDescription>>;
fn load_calibration_parameter_values(
&self,
calibration_id: &str,
) -> Result<IndexMap<String, DataValueDescriptive>>;
fn load_calibration_parameterset(
&self,
calibration_id: &str,
) -> Result<ParameterSet> {
let metadata =
self.load_calibration_parameter_metadata(calibration_id)?;
let descriptions =
self.load_calibration_parameter_descriptions(calibration_id)?;
let values =
self.load_calibration_parameter_values(calibration_id)?;
Ok(ParameterSet {
metadata,
descriptions,
values,
})
}
fn load_calibration_job_index(
&self,
calibration_id: &str,
) -> Result<IndexSet<String>>;
fn load_calibration_job(
&self,
calibration_id: &str,
job_id: &str,
) -> Result<Job>;
fn load_calibration_jobs(
&self,
calibration_id: &str,
) -> Result<IndexMap<String, Job>> {
self.load_calibration_job_index(calibration_id)?
.into_iter()
.map(|job_id| {
let job =
self.load_calibration_job(&calibration_id, &job_id)?;
Ok((job_id, job))
})
.collect::<Result<_>>()
}
fn load_calibration_jobset(
&self,
calibration_id: &str,
board_id: &str,
metadata: Metadata,
runtime_parameters: ParameterSet,
) -> Result<JobSet> {
let device_parameters = self.load_device_parameterset()?;
let board_parameters = self.load_board_parameterset(board_id)?;
let calibration_parameters =
self.load_calibration_parameterset(calibration_id)?;
let parameters = vec![
device_parameters,
board_parameters,
calibration_parameters,
runtime_parameters,
];
let jobs = self.load_calibration_jobs(calibration_id)?;
let channels = self.load_board_mapping(board_id)?;
Ok(JobSet {
metadata,
parameters,
jobs,
channels,
})
}
fn load_sampling_parameter_metadata(
&self,
sampling_id: &str,
) -> Result<ParameterSetMetadata>;
fn load_sampling_parameter_descriptions(
&self,
sampling_id: &str,
) -> Result<IndexMap<String, ParameterDescription>>;
fn load_sampling_parameter_values(
&self,
sampling_id: &str,
) -> Result<IndexMap<String, DataValueDescriptive>>;
fn load_sampling_parameterset(
&self,
sampling_id: &str,
) -> Result<ParameterSet> {
let metadata =
self.load_sampling_parameter_metadata(sampling_id)?;
let descriptions =
self.load_sampling_parameter_descriptions(sampling_id)?;
let values = self.load_sampling_parameter_values(sampling_id)?;
Ok(ParameterSet {
metadata,
descriptions,
values,
})
}
fn load_sampling_job_index(
&self,
sampling_id: &str,
) -> Result<IndexSet<String>>;
fn load_sampling_job(
&self,
sampling_id: &str,
job_id: &str,
) -> Result<Job>;
fn load_sampling_jobs(
&self,
sampling_id: &str,
) -> Result<IndexMap<String, Job>> {
self.load_sampling_job_index(sampling_id)?
.into_iter()
.map(|job_id| {
let job = self.load_sampling_job(&sampling_id, &job_id)?;
Ok((job_id, job))
})
.collect::<Result<_>>()
}
fn load_sampling_jobset(
&self,
sampling_id: &str,
board_id: &str,
metadata: Metadata,
) -> Result<JobSet> {
let device_parameters = self.load_device_parameterset()?;
let board_parameters = self.load_board_parameterset(board_id)?;
let sampling_parameters =
self.load_sampling_parameterset(sampling_id)?;
let parameters =
vec![device_parameters, board_parameters, sampling_parameters];
let jobs = self.load_sampling_jobs(sampling_id)?;
let channels = self.load_board_mapping(board_id)?;
Ok(JobSet {
metadata,
parameters,
jobs,
channels,
})
}
fn load_sampling_jobset_with_runtime_parameters(
&self,
sampling_id: &str,
board_id: &str,
metadata: Metadata,
runtime_parameters: ParameterSet,
) -> Result<JobSet> {
let mut jobset =
self.load_sampling_jobset(sampling_id, board_id, metadata)?;
jobset.parameters.push(runtime_parameters);
Ok(jobset)
}
fn load_sampling_jobset_with_arnalisa_runtime_parameters(
&self,
sampling_id: &str,
board_id: &str,
metadata: Metadata,
runtime_metadata: ParameterSetMetadata,
runtime_parameters: IndexMap<String, arnalisa::Item>,
) -> Result<JobSet> {
let mut jobset =
self.load_sampling_jobset(sampling_id, board_id, metadata)?;
let values = runtime_parameters
.into_iter()
.filter_map(|(k, item)| {
jobset
.parameters
.get_parameter_description(&k)
.map(|description| (k, description, item))
})
.map(|(k, description, item)| {
let value: DataValueDescriptive =
match description.data_type {
DataType::Boolean => {
DataValue::from(item.to_bool().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)?)
}
DataType::Int8 => DataValue::from(
item.to_signed().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)? as i8,
),
DataType::Int16 => DataValue::from(
item.to_signed().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)? as i16,
),
DataType::Int32 => DataValue::from(
item.to_signed().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)? as i32,
),
DataType::Int64 => {
DataValue::from(item.to_signed().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)?)
}
DataType::UInt8 => DataValue::from(
item.to_unsigned().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)? as u8,
),
DataType::UInt16 => DataValue::from(
item.to_unsigned().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)? as u16,
),
DataType::UInt32 => DataValue::from(
item.to_unsigned().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)? as u32,
),
DataType::UInt64 => {
DataValue::from(item.to_unsigned().context(
error::ArnalisaToXioConversion {
name: k.to_string(),
value: item,
datatype: description.data_type,
},
)?)
}
DataType::ParameterMask => {
unimplemented!(
"Cannot convert arnalisa Item \
to ParameterMask"
);
}
DataType::Invalid => {
unimplemented!("Found Invalid datatype");
}
};
Ok((k, value))
})
.collect::<Result<IndexMap<String, DataValueDescriptive>>>()?;
jobset.parameters.push(ParameterSet {
metadata: runtime_metadata,
descriptions: IndexMap::new(),
values,
});
Ok(jobset)
}
}
trait GetParameterDescription {
fn get_parameter_description(
&self,
id: &str,
) -> Option<ParameterDescription>;
}
impl GetParameterDescription for IndexMap<String, ParameterDescription> {
fn get_parameter_description(
&self,
id: &str,
) -> Option<ParameterDescription> {
self.get(&id.to_string()).cloned()
}
}
impl GetParameterDescription for ParameterSet {
fn get_parameter_description(
&self,
id: &str,
) -> Option<ParameterDescription> {
self.descriptions.get_parameter_description(id)
}
}
impl GetParameterDescription for Vec<ParameterSet> {
fn get_parameter_description(
&self,
id: &str,
) -> Option<ParameterDescription> {
self.iter()
.rev()
.filter_map(|parameter_set| {
parameter_set.get_parameter_description(id)
})
.next()
}
}