use crate::core::OError;
#[cfg(feature = "python")]
use pyo3::prelude::*;
use serde::{Deserialize, Serialize, Serializer};
use std::collections::HashMap;
#[derive(Clone, Deserialize, Debug)]
#[serde(untagged)]
pub enum DataValue {
Real(f64),
Integer(i64),
USize(usize),
Vector(Vec<f64>),
DataVector(Vec<DataValue>),
Map(HashMap<String, DataValue>),
}
impl Serialize for DataValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
DataValue::Real(v) => serializer.serialize_f64(*v),
DataValue::Integer(v) => serializer.serialize_i64(*v),
DataValue::USize(v) => serializer.serialize_u64(*v as u64),
DataValue::Vector(v) => serializer.collect_seq(v),
DataValue::DataVector(v) => serializer.collect_seq(v),
DataValue::Map(v) => serializer.collect_map(v),
}
}
}
impl PartialEq for DataValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(DataValue::Real(s), DataValue::Real(o)) => (s.is_nan() && o.is_nan()) || (*s == *o),
(DataValue::Integer(s), DataValue::Integer(o)) => *s == *o,
(DataValue::USize(s), DataValue::USize(o)) => s == o,
(DataValue::Vector(s), DataValue::Vector(o)) => s == o,
_ => false,
}
}
}
impl DataValue {
pub fn as_real(&self) -> Result<f64, OError> {
if let DataValue::Real(v) = self {
Ok(*v)
} else {
Err(OError::WrongDataType("real".to_string()))
}
}
pub fn as_integer(&self) -> Result<i64, OError> {
if let DataValue::Integer(v) = self {
Ok(*v)
} else {
Err(OError::WrongDataType("integer".to_string()))
}
}
pub fn as_f64_vec(&self) -> Result<&Vec<f64>, OError> {
if let DataValue::Vector(v) = self {
Ok(v)
} else {
Err(OError::WrongDataType("vector of f64".to_string()))
}
}
pub fn as_data_vec(&self) -> Result<&Vec<DataValue>, OError> {
if let DataValue::DataVector(v) = self {
Ok(v)
} else {
Err(OError::WrongDataType("vector of data".to_string()))
}
}
pub fn as_map(&self) -> Result<&HashMap<String, DataValue>, OError> {
if let DataValue::Map(v) = self {
Ok(v)
} else {
Err(OError::WrongDataType("map".to_string()))
}
}
pub fn as_usize(&self) -> Result<usize, OError> {
if let DataValue::USize(v) = self {
Ok(*v)
} else {
Err(OError::WrongDataType("usize".to_string()))
}
}
}
#[cfg(feature = "python")]
impl<'py> IntoPyObject<'py> for DataValue {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> PyResult<Self::Output> {
let result = match self {
DataValue::Real(v) => v.into_pyobject(py)?.into_any(),
DataValue::Integer(v) => v.into_pyobject(py)?.into_any(),
DataValue::USize(v) => v.into_pyobject(py)?.into_any(),
DataValue::Vector(v) => v.into_pyobject(py)?.into_any(),
DataValue::DataVector(v) => v.into_pyobject(py)?.into_any(),
DataValue::Map(v) => v.into_pyobject(py)?.into_any(),
};
Ok(result)
}
}