use crate::NaifId;
use crate::{astro::Location, structure::LocationDataSet};
use serde::{Deserialize, Serialize};
use serde_dhall::StaticType;
use std::collections::BTreeMap;
#[cfg(feature = "python")]
use crate::file2heap;
#[cfg(feature = "python")]
use pyo3::exceptions::PyException;
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
use pyo3::types::PyType;
#[cfg(feature = "python")]
use std::path::PathBuf;
use super::{DataSet, DataSetType};
#[derive(Clone, Debug, StaticType, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "anise"))]
pub struct LocationDhallSetEntry {
pub id: Option<NaifId>,
pub alias: Option<String>,
pub value: Location,
}
#[cfg(feature = "python")]
#[cfg_attr(feature = "python", pymethods)]
impl LocationDhallSetEntry {
#[new]
#[pyo3(signature=(value, id=None, alias=None))]
fn py_new(value: Location, id: Option<NaifId>, alias: Option<String>) -> Self {
Self { id, alias, value }
}
#[getter]
fn get_id(&self) -> Option<NaifId> {
self.id
}
#[setter]
fn set_id(&mut self, id: Option<NaifId>) {
self.id = id;
}
#[getter]
fn get_alias(&self) -> Option<String> {
self.alias.clone()
}
#[setter]
fn set_alias(&mut self, alias: Option<String>) {
self.alias = alias;
}
#[getter]
fn get_value(&self) -> Location {
self.value.clone()
}
#[setter]
fn set_value(&mut self, value: Location) {
self.value = value;
}
}
#[derive(Clone, Debug, StaticType, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "anise"))]
pub struct LocationDhallSet {
data: Vec<LocationDhallSetEntry>,
}
impl LocationDhallSet {
pub fn to_dataset(&mut self) -> Result<LocationDataSet, String> {
let mut dataset = DataSet::default();
dataset.metadata.dataset_type = DataSetType::LocationData;
for e in &mut self.data {
e.value.sanitize_mask();
dataset
.push(
e.value.clone(),
e.id,
match e.alias.as_ref() {
Some(s) => Some(s.as_str()),
None => None,
},
)
.map_err(|e| e.to_string())?;
}
Ok(dataset)
}
pub fn from_dhall(repr: &str) -> Result<Self, String> {
let me: Self = serde_dhall::from_str(repr)
.static_type_annotation()
.parse()
.map_err(|e| e.to_string())?;
Ok(me)
}
pub fn to_dhall(&self) -> Result<String, String> {
serde_dhall::serialize(&self)
.static_type_annotation()
.to_string()
.map_err(|e| e.to_string())
}
}
#[cfg(feature = "python")]
#[cfg_attr(feature = "python", pymethods)]
impl LocationDhallSet {
#[new]
fn py_new(data: Vec<LocationDhallSetEntry>) -> Self {
Self { data }
}
#[getter]
fn get_data(&self) -> Vec<LocationDhallSetEntry> {
self.data.clone()
}
#[setter]
fn set_data(&mut self, data: Vec<LocationDhallSetEntry>) {
self.data = data;
}
#[classmethod]
fn loads(_cls: &Bound<'_, PyType>, repr: &str) -> Result<Self, PyErr> {
Self::from_dhall(repr).map_err(PyException::new_err)
}
fn dumps(&self) -> Result<String, PyErr> {
self.to_dhall().map_err(PyException::new_err)
}
#[pyo3(name = "to_dhall")]
fn py_to_dhall(&self) -> Result<String, PyErr> {
self.to_dhall().map_err(PyException::new_err)
}
#[classmethod]
#[pyo3(name = "from_dhall")]
fn py_from_dhall(_cls: Bound<'_, PyType>, repr: &str) -> Result<Self, PyErr> {
Self::from_dhall(repr).map_err(PyException::new_err)
}
#[pyo3(name = "to_dataset")]
fn py_to_dataset(&mut self) -> Result<PyLocationDataSet, PyErr> {
Ok(PyLocationDataSet {
inner: self
.to_dataset()
.map_err(|e| PyException::new_err(e.to_string()))?,
})
}
}
impl LocationDataSet {
pub fn to_dhallset(&self) -> Result<LocationDhallSet, String> {
let mut many_me = BTreeMap::new();
for (id, pos) in &self.lut.by_id {
many_me.insert(
pos,
LocationDhallSetEntry {
id: Some(*id),
alias: None,
value: self.get_by_id(*id).unwrap(),
},
);
}
for (name, pos) in &self.lut.by_name {
if let Some(entry) = many_me.get_mut(&pos) {
entry.alias = Some(name.to_string());
} else {
many_me.insert(
pos,
LocationDhallSetEntry {
id: None,
alias: Some(name.clone()),
value: self.get_by_name(name).unwrap(),
},
);
}
}
let data = many_me
.values()
.cloned()
.collect::<Vec<LocationDhallSetEntry>>();
Ok(LocationDhallSet { data })
}
}
#[cfg(feature = "python")]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "anise"))]
#[pyo3(name = "LocationDataSet")]
pub struct PyLocationDataSet {
inner: LocationDataSet,
}
#[cfg(feature = "python")]
#[cfg_attr(feature = "python", pymethods)]
impl PyLocationDataSet {
#[classmethod]
fn load(_cls: Bound<'_, PyType>, path: &str) -> Result<Self, PyErr> {
let dataset = LocationDataSet::try_from_bytes(
file2heap!(path).map_err(|e| PyException::new_err(e.to_string()))?,
)
.map_err(|e| PyException::new_err(e.to_string()))?;
Ok(Self { inner: dataset })
}
#[pyo3(signature=(path, overwrite=false))]
fn save_as(&mut self, path: &str, overwrite: Option<bool>) -> Result<(), PyErr> {
self.inner.set_crc32();
self.inner
.save_as(&PathBuf::from(path), overwrite.unwrap_or_default())
.map_err(|e| PyException::new_err(e.to_string()))
}
fn to_dhallset(&self) -> Result<LocationDhallSet, PyErr> {
self.inner
.to_dhallset()
.map_err(|e| PyException::new_err(e.to_string()))
}
}
#[cfg(test)]
mod ut_loc_dhall {
use crate::{
astro::{Location, TerrainMask},
constants::frames::EARTH_ITRF93,
};
use super::{LocationDhallSet, LocationDhallSetEntry};
#[test]
fn test_location_dhallset() {
let dss65 = Location {
latitude_deg: 40.427,
longitude_deg: 4.250,
height_km: 0.834,
frame: EARTH_ITRF93.into(),
terrain_mask: vec![],
terrain_mask_ignored: true,
};
let paris = Location {
latitude_deg: 42.0,
longitude_deg: 2.0,
height_km: 0.4,
frame: EARTH_ITRF93.into(),
terrain_mask: vec![TerrainMask {
azimuth_deg: 0.0,
elevation_mask_deg: 15.9,
}],
terrain_mask_ignored: true,
};
let set = LocationDhallSet {
data: vec![
LocationDhallSetEntry {
id: Some(1),
alias: Some("DSS65".to_string()),
value: dss65,
},
LocationDhallSetEntry {
id: None,
alias: Some("Paris".to_string()),
value: paris,
},
],
};
let as_dhall = set.to_dhall().unwrap();
println!("{as_dhall}");
let mut from_dhall = LocationDhallSet::from_dhall(&as_dhall).unwrap();
assert_eq!(from_dhall, set);
let to_dataset = from_dhall.to_dataset().unwrap();
println!("{to_dataset}");
}
}