use serde::{
Serialize, Serializer,
de::{Error, Unexpected},
ser::SerializeStruct,
};
use smallstr::SmallString;
use crate::{DynamicDecimal, Fixed};
use std::{
fmt::{self, Display, Write},
str::FromStr,
};
const FIXED_KEY_TOKEN: &str = "$serde_json::private::Number";
fn serialize_helper<T, S>(value: T, serializer: S) -> Result<S::Ok, S::Error>
where
T: Display,
S: Serializer,
{
let mut string = SmallString::<[u8; 64]>::new();
write!(&mut string, "{}", value).unwrap();
let mut s = serializer.serialize_struct(FIXED_KEY_TOKEN, 1)?;
s.serialize_field(FIXED_KEY_TOKEN, string.as_str())?;
s.end()
}
impl<const P: usize, const S: usize> Serialize for Fixed<P, S> {
fn serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>
where
Ser: Serializer,
{
serialize_helper(self, serializer)
}
}
impl Serialize for DynamicDecimal {
fn serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>
where
Ser: Serializer,
{
serialize_helper(self, serializer)
}
}
impl<'de, const P: usize, const S: usize> serde::Deserialize<'de> for Fixed<P, S> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let decimal = DynamicDecimal::deserialize(deserializer)?;
decimal.try_into().map_err(|_| {
D::Error::custom(format!(
"decimal number {decimal} is outside the value range {} to {} (inclusive)",
Fixed::<P, S>::MIN,
Fixed::<P, S>::MAX
))
})
}
}
impl<'de> serde::Deserialize<'de> for DynamicDecimal {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
deserializer.deserialize_any(DecimalVisitor)
}
}
struct DecimalVisitor;
impl<'de> serde::de::Visitor<'de> for DecimalVisitor {
type Value = DynamicDecimal;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a decimal number")
}
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(DynamicDecimal::from(value))
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(DynamicDecimal::from(value))
}
fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
DynamicDecimal::try_from(value)
.map_err(|_| E::invalid_value(Unexpected::Float(value), &self))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
DynamicDecimal::from_str(value).map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut map = map;
let value = map.next_key::<DecimalKey>()?;
if value.is_none() {
return Err(serde::de::Error::invalid_type(Unexpected::Map, &self));
}
let v: DecimalFromString = map.next_value()?;
Ok(v.value)
}
}
struct DecimalKey;
impl<'de> serde::de::Deserialize<'de> for DecimalKey {
fn deserialize<D>(deserializer: D) -> Result<DecimalKey, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct FieldVisitor;
impl serde::de::Visitor<'_> for FieldVisitor {
type Value = ();
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid FIXED field")
}
fn visit_str<E>(self, s: &str) -> Result<(), E>
where
E: serde::de::Error,
{
if s == FIXED_KEY_TOKEN {
Ok(())
} else {
Err(serde::de::Error::custom("expected field with custom name"))
}
}
}
deserializer.deserialize_identifier(FieldVisitor)?;
Ok(DecimalKey)
}
}
pub struct DecimalFromString {
pub value: DynamicDecimal,
}
impl<'de> serde::de::Deserialize<'de> for DecimalFromString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct Visitor;
impl serde::de::Visitor<'_> for Visitor {
type Value = DecimalFromString;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string containing a decimal number")
}
fn visit_str<E>(self, value: &str) -> Result<DecimalFromString, E>
where
E: serde::de::Error,
{
let d = DynamicDecimal::from_str(value)
.map_err(|_| serde::de::Error::invalid_value(Unexpected::Str(value), &self))?;
Ok(DecimalFromString { value: d })
}
}
deserializer.deserialize_str(Visitor)
}
}
#[cfg(test)]
mod test {
use std::str::FromStr;
use serde_json::json;
use crate::{DynamicDecimal, Fixed};
#[test]
fn serialize_fixed() {
type F = Fixed<10, 2>;
assert_eq!(
serde_json::to_string(&F::try_from(1.23).unwrap()).unwrap(),
json!("1.23")
);
}
#[test]
fn serialize_dynamic() {
assert_eq!(
serde_json::to_string(&DynamicDecimal::from_str("1.23").unwrap()).unwrap(),
json!("1.23")
);
}
#[test]
fn deserialize_fixed() {
type F = Fixed<10, 2>;
assert_eq!(
serde_json::from_str::<F>("1.23").unwrap(),
F::try_from(1.23).unwrap()
);
assert_eq!(
serde_json::from_str::<F>("\"1.23\"").unwrap(),
F::try_from(1.23).unwrap()
);
assert_eq!(
serde_json::from_str::<F>(r#"{"$serde_json::private::Number": "1.23"}"#).unwrap(),
F::try_from(1.23).unwrap()
);
assert_eq!(
serde_json::from_str::<F>("123").unwrap(),
F::try_from(123).unwrap()
);
assert_eq!(
serde_json::from_str::<F>("-123").unwrap(),
F::try_from(-123).unwrap()
);
assert_eq!(
serde_json::from_str::<F>("99999999").unwrap(),
F::try_from(99999999).unwrap()
);
assert!(serde_json::from_str::<F>("999999999").is_err());
}
#[test]
fn deserialize_dynamic() {
assert_eq!(
serde_json::from_str::<DynamicDecimal>("1.23").unwrap(),
DynamicDecimal::try_from(1.23).unwrap()
);
assert_eq!(
serde_json::from_str::<DynamicDecimal>("\"1.23\"").unwrap(),
DynamicDecimal::try_from(1.23).unwrap()
);
assert_eq!(
serde_json::from_str::<DynamicDecimal>(r#"{"$serde_json::private::Number": "1.23"}"#)
.unwrap(),
DynamicDecimal::try_from(1.23).unwrap()
);
assert_eq!(
serde_json::from_str::<DynamicDecimal>("123").unwrap(),
DynamicDecimal::from(123)
);
assert_eq!(
serde_json::from_str::<DynamicDecimal>("-123").unwrap(),
DynamicDecimal::from(-123)
);
assert_eq!(
serde_json::from_str::<DynamicDecimal>("99999999").unwrap(),
DynamicDecimal::from(99999999)
);
assert_eq!(
serde_json::from_str::<DynamicDecimal>("1e38").unwrap(),
DynamicDecimal::try_from(1e38).unwrap()
);
assert!(serde_json::from_str::<DynamicDecimal>("1e39").is_err());
}
}