use alloc::format;
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::Real;
use crate::model::dimension::Dimensioned;
use crate::model::measure::Measure;
use crate::model::quantity::{Quantity, QuantityTag};
use crate::model::unit::Unit;
#[derive(Serialize, Deserialize)]
struct RuntimeQuantity<'a> {
value: Real,
dimensional_vector: [i8; 7],
tag: &'a str,
}
#[derive(Serialize, Deserialize)]
struct RuntimeMeasure<'a> {
value: Real,
unit: &'a str,
}
impl<D: Dimensioned, Tag: QuantityTag> Serialize for Quantity<D, Tag> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let dims = D::to_array();
let rtq = RuntimeQuantity {
value: self.value,
dimensional_vector: dims,
tag: Tag::name(),
};
rtq.serialize(serializer)
}
}
impl<'de, D: Dimensioned, Tag: QuantityTag> Deserialize<'de> for Quantity<D, Tag> {
fn deserialize<DS: Deserializer<'de>>(deserializer: DS) -> Result<Self, DS::Error> {
let rtq = RuntimeQuantity::deserialize(deserializer)?;
let expected = D::to_array();
if rtq.dimensional_vector != expected {
return Err(DS::Error::custom(format!(
"Dimension mismatch: expected {:?}, got {:?}",
expected, rtq.dimensional_vector
)));
}
Ok(Quantity::new(rtq.value))
}
}
impl<U: Unit> Serialize for Measure<U> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let rtm = RuntimeMeasure {
value: self.value,
unit: core::any::type_name::<U>(),
};
rtm.serialize(serializer)
}
}
impl<'de, U: Unit> Deserialize<'de> for Measure<U> {
fn deserialize<DS: Deserializer<'de>>(deserializer: DS) -> Result<Self, DS::Error> {
let rtm = RuntimeMeasure::deserialize(deserializer)?;
let expected = core::any::type_name::<U>();
if rtm.unit != expected {
return Err(DS::Error::custom(format!(
"Unit mismatch: expected '{}', got '{}'",
expected, rtm.unit
)));
}
Ok(Measure::new(rtm.value))
}
}
#[cfg(test)]
mod tests {
use crate::model::measure::Measure;
use crate::model::unit::Unit;
use crate::system::*;
#[test]
fn test_quantity_serde() {
let f = Force::new(42.0);
let json = serde_json::to_string(&f).unwrap();
assert_eq!(
json,
"{\"value\":42.0,\"dimensional_vector\":[1,1,-2,0,0,0,0],\"tag\":\"()\"}"
);
let f2: Force = serde_json::from_str(&json).unwrap();
assert_eq!(f, f2);
let err: Result<Energy, _> = serde_json::from_str(&json);
assert!(err.is_err());
}
#[test]
#[cfg(feature = "quantity_tags")]
fn test_quantity_serde_withtag() {
let f = SolidAngle::new(42.0);
let json = serde_json::to_string(&f).unwrap();
assert_eq!(
json,
"{\"value\":42.0,\"dimensional_vector\":[0,0,0,0,0,0,0],\"tag\":\"SolidAngle\"}"
);
}
#[test]
fn test_measure_serde() {
let f = Kilonewton::new(42.0);
let json = serde_json::to_string(&f).unwrap();
assert_eq!(
json,
"{\"value\":42.0,\"unit\":\"ferrunitas::system::defs::mechanics::Kilonewton\"}"
);
let f2: Measure<Kilonewton> = serde_json::from_str(&json).unwrap();
assert_eq!(f, f2);
let err: Result<Measure<Milliwatt>, _> = serde_json::from_str(&json);
assert!(err.is_err());
}
}