use crate::scalar::{Real, Scalar};
use crate::{Quantity, Unit};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
impl<U: Unit, S: Real> Serialize for Quantity<U, S> {
fn serialize<Ser>(&self, serializer: Ser) -> core::result::Result<Ser::Ok, Ser::Error>
where
Ser: Serializer,
{
self.value().to_f64().serialize(serializer)
}
}
impl<'de, U: Unit, S: Real> Deserialize<'de> for Quantity<U, S> {
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = f64::deserialize(deserializer)?;
Ok(Quantity::new(S::from_f64(value)))
}
}
pub mod serde_scalar {
use super::*;
#[allow(dead_code)]
pub fn serialize<U, S, Ser>(
quantity: &Quantity<U, S>,
serializer: Ser,
) -> Result<Ser::Ok, Ser::Error>
where
U: Unit,
S: Scalar + Serialize,
Ser: Serializer,
{
quantity.value_ref().serialize(serializer)
}
#[allow(dead_code)]
pub fn deserialize<'de, U, S, D>(deserializer: D) -> Result<Quantity<U, S>, D::Error>
where
U: Unit,
S: Scalar + Deserialize<'de>,
D: Deserializer<'de>,
{
let value = S::deserialize(deserializer)?;
Ok(Quantity::new(value))
}
}
#[cfg(feature = "std")]
pub mod serde_with_unit {
extern crate alloc;
use alloc::format;
use alloc::string::String;
use super::*;
use serde::de::{self, Deserializer, MapAccess, Visitor};
use serde::ser::{SerializeStruct, Serializer};
pub fn serialize<U, S, Ser>(
quantity: &Quantity<U, S>,
serializer: Ser,
) -> Result<Ser::Ok, Ser::Error>
where
U: Unit,
S: Real,
Ser: Serializer,
{
let mut state = serializer.serialize_struct("Quantity", 2)?;
state.serialize_field("value", &quantity.value().to_f64())?;
state.serialize_field("unit", U::SYMBOL)?;
state.end()
}
pub fn deserialize<'de, U, S, D>(deserializer: D) -> Result<Quantity<U, S>, D::Error>
where
U: Unit,
S: Real,
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum Field {
Value,
Unit,
}
struct QuantityVisitor<U, S>(core::marker::PhantomData<(U, S)>);
impl<'de, U: Unit, S: Real> Visitor<'de> for QuantityVisitor<U, S> {
type Value = Quantity<U, S>;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str("struct Quantity with value and unit fields")
}
fn visit_map<V>(self, mut map: V) -> Result<Quantity<U, S>, V::Error>
where
V: MapAccess<'de>,
{
let mut value: Option<f64> = None;
let mut unit: Option<String> = None;
while let Some(key) = map.next_key()? {
match key {
Field::Value => {
if value.is_some() {
return Err(de::Error::duplicate_field("value"));
}
value = Some(map.next_value()?);
}
Field::Unit => {
if unit.is_some() {
return Err(de::Error::duplicate_field("unit"));
}
unit = Some(map.next_value()?);
}
}
}
let value = value.ok_or_else(|| de::Error::missing_field("value"))?;
if let Some(ref unit_str) = unit {
if unit_str != U::SYMBOL {
return Err(de::Error::custom(format!(
"unit mismatch: expected '{}', found '{}'",
U::SYMBOL,
unit_str
)));
}
}
Ok(Quantity::new(S::from_f64(value)))
}
}
deserializer.deserialize_struct(
"Quantity",
&["value", "unit"],
QuantityVisitor(core::marker::PhantomData),
)
}
}