use std::fmt;
use std::marker::PhantomData;
use std::str::FromStr;
use ::serde::{Deserialize, Deserializer, Serialize, Serializer, de};
use crate::{BaseMoney, Currency, Decimal, RawMoney};
impl<C: Currency + Clone> Serialize for RawMoney<C> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let n = serde_json::Number::from_str(&self.amount().to_string())
.map_err(|_| ::serde::ser::Error::custom("cannot convert Decimal to JSON Number"))?;
n.serialize(serializer)
}
}
struct RawMoneyVisitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for RawMoneyVisitor<C> {
type Value = RawMoney<C>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a number")
}
fn visit_f64<E: de::Error>(self, v: f64) -> Result<Self::Value, E> {
RawMoney::<C>::new(v).map_err(de::Error::custom)
}
fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
RawMoney::<C>::new(v).map_err(de::Error::custom)
}
fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
RawMoney::<C>::new(i128::from(v)).map_err(de::Error::custom)
}
fn visit_i128<E: de::Error>(self, v: i128) -> Result<Self::Value, E> {
RawMoney::<C>::new(v).map_err(de::Error::custom)
}
fn visit_u128<E: de::Error>(self, v: u128) -> Result<Self::Value, E> {
i128::try_from(v)
.map_err(|_| de::Error::custom("value too large for RawMoney"))
.and_then(|n| RawMoney::<C>::new(n).map_err(de::Error::custom))
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
Decimal::from_str(v)
.map(|d| RawMoney::<C>::from_decimal(d))
.map_err(|_| de::Error::custom(format!("invalid decimal: {}", v)))
}
fn visit_map<A: de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
const ARBITRARY_NUMBER_KEY: &str = "$serde_json::private::Number";
if let Ok(Some(key)) = map.next_key::<String>()
&& key == ARBITRARY_NUMBER_KEY
{
let value: String = map.next_value()?;
let d = Decimal::from_str(&value)
.map_err(|_| de::Error::custom(format!("invalid decimal: {}", value)))?;
Ok(RawMoney::<C>::from_decimal(d))
} else {
Err(de::Error::custom("unexpected key"))
}
}
}
impl<'de, C: Currency + Clone> Deserialize<'de> for RawMoney<C> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_any(RawMoneyVisitor(PhantomData))
}
}
pub mod comma_str_code {
use std::fmt;
use std::marker::PhantomData;
use std::str::FromStr;
use ::serde::{Deserializer, Serializer, de};
use crate::{BaseMoney, Currency, RawMoney};
pub fn serialize<C: Currency + Clone, S: Serializer>(
value: &RawMoney<C>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&value.format_code())
}
struct Visitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for Visitor<C> {
type Value = RawMoney<C>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string like 'USD 1,234.56789'")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
RawMoney::<C>::from_str(v).map_err(de::Error::custom)
}
}
pub fn deserialize<'de, C: Currency + Clone, D: Deserializer<'de>>(
deserializer: D,
) -> Result<RawMoney<C>, D::Error> {
deserializer.deserialize_str(Visitor(PhantomData))
}
}
pub mod option_comma_str_code {
use std::fmt;
use std::marker::PhantomData;
use ::serde::{Deserializer, Serializer, de};
use crate::{BaseMoney, Currency, RawMoney};
pub fn serialize<C: Currency + Clone, S: Serializer>(
value: &Option<RawMoney<C>>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match value {
Some(m) => serializer.serialize_some(m.format_code().as_str()),
None => serializer.serialize_none(),
}
}
struct Visitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for Visitor<C> {
type Value = Option<RawMoney<C>>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string like 'USD 1,234.56789' or null")
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_some<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
super::comma_str_code::deserialize(d).map(Some)
}
}
pub fn deserialize<'de, C: Currency + Clone, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<RawMoney<C>>, D::Error> {
deserializer.deserialize_option(Visitor(PhantomData))
}
}
pub mod comma_str_symbol {
use std::fmt;
use std::marker::PhantomData;
use ::serde::{Deserializer, Serializer, de};
use crate::{BaseMoney, Currency, RawMoney};
pub fn serialize<C: Currency + Clone, S: Serializer>(
value: &RawMoney<C>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&value.format_symbol())
}
struct Visitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for Visitor<C> {
type Value = RawMoney<C>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string like '$1,234.56789'")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
RawMoney::<C>::from_symbol_comma_thousands(v).map_err(|err| E::custom(err))
}
}
pub fn deserialize<'de, C: Currency + Clone, D: Deserializer<'de>>(
deserializer: D,
) -> Result<RawMoney<C>, D::Error> {
deserializer.deserialize_str(Visitor(PhantomData))
}
}
pub mod option_comma_str_symbol {
use std::fmt;
use std::marker::PhantomData;
use ::serde::{Deserializer, Serializer, de};
use crate::{BaseMoney, Currency, RawMoney};
pub fn serialize<C: Currency + Clone, S: Serializer>(
value: &Option<RawMoney<C>>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match value {
Some(m) => serializer.serialize_some(m.format_symbol().as_str()),
None => serializer.serialize_none(),
}
}
struct Visitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for Visitor<C> {
type Value = Option<RawMoney<C>>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string like '$1,234.56789' or null")
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_some<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
super::comma_str_symbol::deserialize(d).map(Some)
}
}
pub fn deserialize<'de, C: Currency + Clone, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<RawMoney<C>>, D::Error> {
deserializer.deserialize_option(Visitor(PhantomData))
}
}
pub mod dot_str_code {
use std::fmt;
use std::marker::PhantomData;
use ::serde::{Deserializer, Serializer, de};
use crate::{BaseMoney, Currency, RawMoney};
pub fn serialize<C: Currency + Clone, S: Serializer>(
value: &RawMoney<C>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&value.format_code())
}
struct Visitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for Visitor<C> {
type Value = RawMoney<C>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string like 'EUR 1.234,56789'")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
RawMoney::<C>::from_str_dot_thousands(v).map_err(de::Error::custom)
}
}
pub fn deserialize<'de, C: Currency + Clone, D: Deserializer<'de>>(
deserializer: D,
) -> Result<RawMoney<C>, D::Error> {
deserializer.deserialize_str(Visitor(PhantomData))
}
}
pub mod option_dot_str_code {
use std::fmt;
use std::marker::PhantomData;
use ::serde::{Deserializer, Serializer, de};
use crate::{BaseMoney, Currency, RawMoney};
pub fn serialize<C: Currency + Clone, S: Serializer>(
value: &Option<RawMoney<C>>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match value {
Some(m) => serializer.serialize_some(m.format_code().as_str()),
None => serializer.serialize_none(),
}
}
struct Visitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for Visitor<C> {
type Value = Option<RawMoney<C>>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string like 'EUR 1.234,56789' or null")
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_some<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
super::dot_str_code::deserialize(d).map(Some)
}
}
pub fn deserialize<'de, C: Currency + Clone, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<RawMoney<C>>, D::Error> {
deserializer.deserialize_option(Visitor(PhantomData))
}
}
pub mod dot_str_symbol {
use std::fmt;
use std::marker::PhantomData;
use ::serde::{Deserializer, Serializer, de};
use crate::{BaseMoney, Currency, RawMoney};
pub fn serialize<C: Currency + Clone, S: Serializer>(
value: &RawMoney<C>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&value.format_symbol())
}
struct Visitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for Visitor<C> {
type Value = RawMoney<C>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string like '€1.234,56789'")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
RawMoney::<C>::from_symbol_dot_thousands(v).map_err(|err| E::custom(err))
}
}
pub fn deserialize<'de, C: Currency + Clone, D: Deserializer<'de>>(
deserializer: D,
) -> Result<RawMoney<C>, D::Error> {
deserializer.deserialize_str(Visitor(PhantomData))
}
}
pub mod option_dot_str_symbol {
use std::fmt;
use std::marker::PhantomData;
use ::serde::{Deserializer, Serializer, de};
use crate::{BaseMoney, Currency, RawMoney};
pub fn serialize<C: Currency + Clone, S: Serializer>(
value: &Option<RawMoney<C>>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match value {
Some(m) => serializer.serialize_some(m.format_symbol().as_str()),
None => serializer.serialize_none(),
}
}
struct Visitor<C>(PhantomData<C>);
impl<'de, C: Currency + Clone> de::Visitor<'de> for Visitor<C> {
type Value = Option<RawMoney<C>>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string like '€1.234,56789' or null")
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_some<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
super::dot_str_symbol::deserialize(d).map(Some)
}
}
pub fn deserialize<'de, C: Currency + Clone, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<RawMoney<C>>, D::Error> {
deserializer.deserialize_option(Visitor(PhantomData))
}
}