diff options
Diffstat (limited to 'third_party/rust/rust_decimal/src/serde.rs')
-rw-r--r-- | third_party/rust/rust_decimal/src/serde.rs | 899 |
1 files changed, 899 insertions, 0 deletions
diff --git a/third_party/rust/rust_decimal/src/serde.rs b/third_party/rust/rust_decimal/src/serde.rs new file mode 100644 index 0000000000..ce876309f9 --- /dev/null +++ b/third_party/rust/rust_decimal/src/serde.rs @@ -0,0 +1,899 @@ +use crate::Decimal; +use alloc::string::ToString; +use core::{fmt, str::FromStr}; +use num_traits::FromPrimitive; +use serde::{self, de::Unexpected}; + +/// Serialize/deserialize Decimals as arbitrary precision numbers in JSON using the `arbitrary_precision` feature within `serde_json`. +/// +/// ``` +/// # use serde::{Serialize, Deserialize}; +/// # use rust_decimal::Decimal; +/// # use std::str::FromStr; +/// +/// #[derive(Serialize, Deserialize)] +/// pub struct ArbitraryExample { +/// #[serde(with = "rust_decimal::serde::arbitrary_precision")] +/// value: Decimal, +/// } +/// +/// let value = ArbitraryExample { value: Decimal::from_str("123.400").unwrap() }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":123.400}"# +/// ); +/// ``` +#[cfg(feature = "serde-with-arbitrary-precision")] +pub mod arbitrary_precision { + use super::*; + use serde::Serialize; + + pub fn deserialize<'de, D>(deserializer: D) -> Result<Decimal, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_any(DecimalVisitor) + } + + pub fn serialize<S>(value: &Decimal, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + serde_json::Number::from_str(&value.to_string()) + .map_err(serde::ser::Error::custom)? + .serialize(serializer) + } +} + +/// Serialize/deserialize optional Decimals as arbitrary precision numbers in JSON using the `arbitrary_precision` feature within `serde_json`. +/// +/// ``` +/// # use serde::{Serialize, Deserialize}; +/// # use rust_decimal::Decimal; +/// # use std::str::FromStr; +/// +/// #[derive(Serialize, Deserialize)] +/// pub struct ArbitraryExample { +/// #[serde(with = "rust_decimal::serde::arbitrary_precision_option")] +/// value: Option<Decimal>, +/// } +/// +/// let value = ArbitraryExample { value: Some(Decimal::from_str("123.400").unwrap()) }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":123.400}"# +/// ); +/// +/// let value = ArbitraryExample { value: None }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":null}"# +/// ); +/// ``` +#[cfg(feature = "serde-with-arbitrary-precision")] +pub mod arbitrary_precision_option { + use super::*; + use serde::Serialize; + + pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_option(OptionDecimalVisitor) + } + + pub fn serialize<S>(value: &Option<Decimal>, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + match *value { + Some(ref decimal) => serde_json::Number::from_str(&decimal.to_string()) + .map_err(serde::ser::Error::custom)? + .serialize(serializer), + None => serializer.serialize_none(), + } + } +} + +/// Serialize/deserialize Decimals as floats. +/// +/// ``` +/// # use serde::{Serialize, Deserialize}; +/// # use rust_decimal::Decimal; +/// # use std::str::FromStr; +/// +/// #[derive(Serialize, Deserialize)] +/// pub struct FloatExample { +/// #[serde(with = "rust_decimal::serde::float")] +/// value: Decimal, +/// } +/// +/// let value = FloatExample { value: Decimal::from_str("123.400").unwrap() }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":123.4}"# +/// ); +/// ``` +#[cfg(feature = "serde-with-float")] +pub mod float { + use super::*; + use serde::Serialize; + + pub fn deserialize<'de, D>(deserializer: D) -> Result<Decimal, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_any(DecimalVisitor) + } + + pub fn serialize<S>(value: &Decimal, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + use num_traits::ToPrimitive; + value.to_f64().unwrap().serialize(serializer) + } +} + +/// Serialize/deserialize optional Decimals as floats. +/// +/// ``` +/// # use serde::{Serialize, Deserialize}; +/// # use rust_decimal::Decimal; +/// # use std::str::FromStr; +/// +/// #[derive(Serialize, Deserialize)] +/// pub struct FloatExample { +/// #[serde(with = "rust_decimal::serde::float_option")] +/// value: Option<Decimal>, +/// } +/// +/// let value = FloatExample { value: Some(Decimal::from_str("123.400").unwrap()) }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":123.4}"# +/// ); +/// +/// let value = FloatExample { value: None }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":null}"# +/// ); +/// ``` +#[cfg(feature = "serde-with-float")] +pub mod float_option { + use super::*; + use serde::Serialize; + + pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_option(OptionDecimalVisitor) + } + + pub fn serialize<S>(value: &Option<Decimal>, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + match *value { + Some(ref decimal) => { + use num_traits::ToPrimitive; + decimal.to_f64().unwrap().serialize(serializer) + } + None => serializer.serialize_none(), + } + } +} + +/// Serialize/deserialize Decimals as strings. This is particularly useful when using binary encoding formats. +/// +/// ``` +/// # use serde::{Serialize, Deserialize}; +/// # use rust_decimal::Decimal; +/// # use std::str::FromStr; +/// +/// #[derive(Serialize, Deserialize)] +/// pub struct StringExample { +/// #[serde(with = "rust_decimal::serde::str")] +/// value: Decimal, +/// } +/// +/// let value = StringExample { value: Decimal::from_str("123.400").unwrap() }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":"123.400"}"# +/// ); +/// +/// ``` +#[cfg(feature = "serde-with-str")] +pub mod str { + use super::*; + + pub fn deserialize<'de, D>(deserializer: D) -> Result<Decimal, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_str(DecimalVisitor) + } + + pub fn serialize<S>(value: &Decimal, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + let value = crate::str::to_str_internal(value, true, None); + serializer.serialize_str(value.0.as_ref()) + } +} + +/// Serialize/deserialize optional Decimals as strings. This is particularly useful when using binary encoding formats. +/// +/// ``` +/// # use serde::{Serialize, Deserialize}; +/// # use rust_decimal::Decimal; +/// # use std::str::FromStr; +/// +/// #[derive(Serialize, Deserialize)] +/// pub struct StringExample { +/// #[serde(with = "rust_decimal::serde::str_option")] +/// value: Option<Decimal>, +/// } +/// +/// let value = StringExample { value: Some(Decimal::from_str("123.400").unwrap()) }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":"123.400"}"# +/// ); +/// +/// let value = StringExample { value: None }; +/// assert_eq!( +/// &serde_json::to_string(&value).unwrap(), +/// r#"{"value":null}"# +/// ); +/// ``` +#[cfg(feature = "serde-with-str")] +pub mod str_option { + use super::*; + + pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_option(OptionDecimalStrVisitor) + } + + pub fn serialize<S>(value: &Option<Decimal>, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + match *value { + Some(ref decimal) => { + let decimal = crate::str::to_str_internal(decimal, true, None); + serializer.serialize_some(decimal.0.as_ref()) + } + None => serializer.serialize_none(), + } + } +} + +#[cfg(not(feature = "serde-str"))] +impl<'de> serde::Deserialize<'de> for Decimal { + fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_any(DecimalVisitor) + } +} + +#[cfg(all(feature = "serde-str", not(feature = "serde-float")))] +impl<'de> serde::Deserialize<'de> for Decimal { + fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_str(DecimalVisitor) + } +} + +#[cfg(all(feature = "serde-str", feature = "serde-float"))] +impl<'de> serde::Deserialize<'de> for Decimal { + fn deserialize<D>(deserializer: D) -> Result<Decimal, D::Error> + where + D: serde::de::Deserializer<'de>, + { + deserializer.deserialize_f64(DecimalVisitor) + } +} + +// It's a shame this needs to be redefined for this feature and not able to be referenced directly +#[cfg(feature = "serde-with-arbitrary-precision")] +const DECIMAL_KEY_TOKEN: &str = "$serde_json::private::Number"; + +struct DecimalVisitor; + +impl<'de> serde::de::Visitor<'de> for DecimalVisitor { + type Value = Decimal; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a Decimal type representing a fixed-point number") + } + + fn visit_i64<E>(self, value: i64) -> Result<Decimal, E> + where + E: serde::de::Error, + { + match Decimal::from_i64(value) { + Some(s) => Ok(s), + None => Err(E::invalid_value(Unexpected::Signed(value), &self)), + } + } + + fn visit_u64<E>(self, value: u64) -> Result<Decimal, E> + where + E: serde::de::Error, + { + match Decimal::from_u64(value) { + Some(s) => Ok(s), + None => Err(E::invalid_value(Unexpected::Unsigned(value), &self)), + } + } + + fn visit_f64<E>(self, value: f64) -> Result<Decimal, E> + where + E: serde::de::Error, + { + Decimal::from_str(&value.to_string()).map_err(|_| E::invalid_value(Unexpected::Float(value), &self)) + } + + fn visit_str<E>(self, value: &str) -> Result<Decimal, E> + where + E: serde::de::Error, + { + Decimal::from_str(value) + .or_else(|_| Decimal::from_scientific(value)) + .map_err(|_| E::invalid_value(Unexpected::Str(value), &self)) + } + + #[cfg(feature = "serde-with-arbitrary-precision")] + fn visit_map<A>(self, map: A) -> Result<Decimal, 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 OptionDecimalVisitor; + +impl<'de> serde::de::Visitor<'de> for OptionDecimalVisitor { + type Value = Option<Decimal>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a Decimal type representing a fixed-point number") + } + + fn visit_none<E>(self) -> Result<Option<Decimal>, E> + where + E: serde::de::Error, + { + Ok(None) + } + + #[cfg(all(feature = "serde-str", feature = "serde-float"))] + fn visit_some<D>(self, d: D) -> Result<Option<Decimal>, D::Error> + where + D: serde::de::Deserializer<'de>, + { + // We've got multiple types that we may see so we need to use any + d.deserialize_any(DecimalVisitor).map(Some) + } + + #[cfg(not(all(feature = "serde-str", feature = "serde-float")))] + fn visit_some<D>(self, d: D) -> Result<Option<Decimal>, D::Error> + where + D: serde::de::Deserializer<'de>, + { + <Decimal as serde::Deserialize>::deserialize(d).map(Some) + } +} + +#[cfg(feature = "serde-with-str")] +struct OptionDecimalStrVisitor; + +#[cfg(feature = "serde-with-str")] +impl<'de> serde::de::Visitor<'de> for OptionDecimalStrVisitor { + type Value = Option<Decimal>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a Decimal type representing a fixed-point number") + } + + fn visit_none<E>(self) -> Result<Option<Decimal>, E> + where + E: serde::de::Error, + { + Ok(None) + } + + fn visit_some<D>(self, d: D) -> Result<Option<Decimal>, D::Error> + where + D: serde::de::Deserializer<'de>, + { + d.deserialize_str(DecimalVisitor).map(Some) + } +} + +#[cfg(feature = "serde-with-arbitrary-precision")] +struct DecimalKey; + +#[cfg(feature = "serde-with-arbitrary-precision")] +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<'de> serde::de::Visitor<'de> for FieldVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a valid decimal field") + } + + fn visit_str<E>(self, s: &str) -> Result<(), E> + where + E: serde::de::Error, + { + if s == DECIMAL_KEY_TOKEN { + Ok(()) + } else { + Err(serde::de::Error::custom("expected field with custom name")) + } + } + } + + deserializer.deserialize_identifier(FieldVisitor)?; + Ok(DecimalKey) + } +} + +#[cfg(feature = "serde-with-arbitrary-precision")] +pub struct DecimalFromString { + pub value: Decimal, +} + +#[cfg(feature = "serde-with-arbitrary-precision")] +impl<'de> serde::de::Deserialize<'de> for DecimalFromString { + fn deserialize<D>(deserializer: D) -> Result<DecimalFromString, D::Error> + where + D: serde::de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = DecimalFromString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("string containing a decimal") + } + + fn visit_str<E>(self, value: &str) -> Result<DecimalFromString, E> + where + E: serde::de::Error, + { + let d = Decimal::from_str(value) + .or_else(|_| Decimal::from_scientific(value)) + .map_err(serde::de::Error::custom)?; + Ok(DecimalFromString { value: d }) + } + } + + deserializer.deserialize_str(Visitor) + } +} + +#[cfg(not(feature = "serde-float"))] +impl serde::Serialize for Decimal { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + let value = crate::str::to_str_internal(self, true, None); + serializer.serialize_str(value.0.as_ref()) + } +} + +#[cfg(all(feature = "serde-float", not(feature = "serde-arbitrary-precision")))] +impl serde::Serialize for Decimal { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + use num_traits::ToPrimitive; + serializer.serialize_f64(self.to_f64().unwrap()) + } +} + +#[cfg(all(feature = "serde-float", feature = "serde-arbitrary-precision"))] +impl serde::Serialize for Decimal { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + serde_json::Number::from_str(&self.to_string()) + .map_err(serde::ser::Error::custom)? + .serialize(serializer) + } +} + +#[cfg(test)] +mod test { + use super::*; + use serde::{Deserialize, Serialize}; + + #[derive(Serialize, Deserialize, Debug)] + struct Record { + amount: Decimal, + } + + #[test] + #[cfg(not(feature = "serde-str"))] + fn deserialize_valid_decimal() { + let data = [ + ("{\"amount\":\"1.234\"}", "1.234"), + ("{\"amount\":1234}", "1234"), + ("{\"amount\":1234.56}", "1234.56"), + ("{\"amount\":\"1.23456e3\"}", "1234.56"), + ]; + for &(serialized, value) in data.iter() { + let result = serde_json::from_str(serialized); + assert_eq!( + true, + result.is_ok(), + "expected successful deserialization for {}. Error: {:?}", + serialized, + result.err().unwrap() + ); + let record: Record = result.unwrap(); + assert_eq!( + value, + record.amount.to_string(), + "expected: {}, actual: {}", + value, + record.amount.to_string() + ); + } + } + + #[test] + #[cfg(feature = "serde-arbitrary-precision")] + fn deserialize_basic_decimal() { + let d: Decimal = serde_json::from_str("1.1234127836128763").unwrap(); + // Typically, this would not work without this feature enabled due to rounding + assert_eq!(d.to_string(), "1.1234127836128763"); + } + + #[test] + #[should_panic] + fn deserialize_invalid_decimal() { + let serialized = "{\"amount\":\"foo\"}"; + let _: Record = serde_json::from_str(serialized).unwrap(); + } + + #[test] + #[cfg(not(feature = "serde-float"))] + fn serialize_decimal() { + let record = Record { + amount: Decimal::new(1234, 3), + }; + let serialized = serde_json::to_string(&record).unwrap(); + assert_eq!("{\"amount\":\"1.234\"}", serialized); + } + + #[test] + #[cfg(not(feature = "serde-float"))] + fn serialize_negative_zero() { + let record = Record { amount: -Decimal::ZERO }; + let serialized = serde_json::to_string(&record).unwrap(); + assert_eq!("{\"amount\":\"-0\"}", serialized); + } + + #[test] + #[cfg(feature = "serde-float")] + fn serialize_decimal() { + let record = Record { + amount: Decimal::new(1234, 3), + }; + let serialized = serde_json::to_string(&record).unwrap(); + assert_eq!("{\"amount\":1.234}", serialized); + } + + #[test] + #[cfg(all(feature = "serde-float", feature = "serde-arbitrary-precision"))] + fn serialize_decimal_roundtrip() { + let record = Record { + // 4.81 is intentionally chosen as it is unrepresentable as a floating point number, meaning this test + // would fail if the `serde-arbitrary-precision` was not activated. + amount: Decimal::new(481, 2), + }; + let serialized = serde_json::to_string(&record).unwrap(); + assert_eq!("{\"amount\":4.81}", serialized); + let deserialized: Record = serde_json::from_str(&serialized).unwrap(); + assert_eq!(record.amount, deserialized.amount); + } + + #[test] + #[cfg(all(feature = "serde-str", not(feature = "serde-float")))] + fn serialize_decimal_roundtrip() { + let record = Record { + amount: Decimal::new(481, 2), + }; + let serialized = serde_json::to_string(&record).unwrap(); + assert_eq!("{\"amount\":\"4.81\"}", serialized); + let deserialized: Record = serde_json::from_str(&serialized).unwrap(); + assert_eq!(record.amount, deserialized.amount); + } + + #[test] + #[cfg(all(feature = "serde-str", not(feature = "serde-float")))] + fn bincode_serialization() { + use bincode::{deserialize, serialize}; + + let data = [ + "0", + "0.00", + "3.14159", + "-3.14159", + "1234567890123.4567890", + "-1234567890123.4567890", + "5233.9008808150288439427720175", + "-5233.9008808150288439427720175", + ]; + for &raw in data.iter() { + let value = Decimal::from_str(raw).unwrap(); + let encoded = serialize(&value).unwrap(); + let decoded: Decimal = deserialize(&encoded[..]).unwrap(); + assert_eq!(value, decoded); + assert_eq!(8usize + raw.len(), encoded.len()); + } + } + + #[test] + #[cfg(all(feature = "serde-str", feature = "serde-float"))] + fn bincode_serialization() { + use bincode::{deserialize, serialize}; + + let data = [ + ("0", "0"), + ("0.00", "0.00"), + ("3.14159", "3.14159"), + ("-3.14159", "-3.14159"), + ("1234567890123.4567890", "1234567890123.4568"), + ("-1234567890123.4567890", "-1234567890123.4568"), + ]; + for &(value, expected) in data.iter() { + let value = Decimal::from_str(value).unwrap(); + let expected = Decimal::from_str(expected).unwrap(); + let encoded = serialize(&value).unwrap(); + let decoded: Decimal = deserialize(&encoded[..]).unwrap(); + assert_eq!(expected, decoded); + assert_eq!(8usize, encoded.len()); + } + } + + #[test] + #[cfg(all(feature = "serde-str", not(feature = "serde-float")))] + fn bincode_nested_serialization() { + // Issue #361 + #[derive(Deserialize, Serialize, Debug)] + pub struct Foo { + value: Decimal, + } + + let s = Foo { + value: Decimal::new(-1, 3).round_dp(0), + }; + let ser = bincode::serialize(&s).unwrap(); + let des: Foo = bincode::deserialize(&ser).unwrap(); + assert_eq!(des.value, s.value); + } + + #[test] + #[cfg(feature = "serde-with-arbitrary-precision")] + fn with_arbitrary_precision() { + #[derive(Serialize, Deserialize)] + pub struct ArbitraryExample { + #[serde(with = "crate::serde::arbitrary_precision")] + value: Decimal, + } + + let value = ArbitraryExample { + value: Decimal::from_str("123.400").unwrap(), + }; + assert_eq!(&serde_json::to_string(&value).unwrap(), r#"{"value":123.400}"#); + } + + #[test] + #[cfg(feature = "serde-with-arbitrary-precision")] + fn with_arbitrary_precision_from_string() { + #[derive(Serialize, Deserialize)] + pub struct ArbitraryExample { + #[serde(with = "crate::serde::arbitrary_precision")] + value: Decimal, + } + + let value: ArbitraryExample = serde_json::from_str(r#"{"value":"1.1234127836128763"}"#).unwrap(); + assert_eq!(value.value.to_string(), "1.1234127836128763"); + } + + #[test] + #[cfg(feature = "serde-with-float")] + fn with_float() { + #[derive(Serialize, Deserialize)] + pub struct FloatExample { + #[serde(with = "crate::serde::float")] + value: Decimal, + } + + let value = FloatExample { + value: Decimal::from_str("123.400").unwrap(), + }; + assert_eq!(&serde_json::to_string(&value).unwrap(), r#"{"value":123.4}"#); + } + + #[test] + #[cfg(feature = "serde-with-str")] + fn with_str() { + #[derive(Serialize, Deserialize)] + pub struct StringExample { + #[serde(with = "crate::serde::str")] + value: Decimal, + } + + let value = StringExample { + value: Decimal::from_str("123.400").unwrap(), + }; + assert_eq!(&serde_json::to_string(&value).unwrap(), r#"{"value":"123.400"}"#); + } + + #[test] + #[cfg(feature = "serde-with-str")] + fn with_str_bincode() { + use bincode::{deserialize, serialize}; + + #[derive(Serialize, Deserialize)] + struct BincodeExample { + #[serde(with = "crate::serde::str")] + value: Decimal, + } + + let data = [ + ("0", "0"), + ("0.00", "0.00"), + ("1.234", "1.234"), + ("3.14159", "3.14159"), + ("-3.14159", "-3.14159"), + ("1234567890123.4567890", "1234567890123.4567890"), + ("-1234567890123.4567890", "-1234567890123.4567890"), + ]; + for &(value, expected) in data.iter() { + let value = Decimal::from_str(value).unwrap(); + let expected = Decimal::from_str(expected).unwrap(); + let input = BincodeExample { value }; + + let encoded = serialize(&input).unwrap(); + let decoded: BincodeExample = deserialize(&encoded[..]).unwrap(); + assert_eq!(expected, decoded.value); + } + } + + #[test] + #[cfg(feature = "serde-with-str")] + fn with_str_bincode_optional() { + use bincode::{deserialize, serialize}; + + #[derive(Serialize, Deserialize)] + struct BincodeExample { + #[serde(with = "crate::serde::str_option")] + value: Option<Decimal>, + } + + // Some(value) + let value = Some(Decimal::new(1234, 3)); + let input = BincodeExample { value }; + let encoded = serialize(&input).unwrap(); + let decoded: BincodeExample = deserialize(&encoded[..]).unwrap(); + assert_eq!(value, decoded.value, "Some(value)"); + + // None + let input = BincodeExample { value: None }; + let encoded = serialize(&input).unwrap(); + let decoded: BincodeExample = deserialize(&encoded[..]).unwrap(); + assert_eq!(None, decoded.value, "None"); + } + + #[test] + #[cfg(feature = "serde-with-str")] + fn with_str_optional() { + #[derive(Serialize, Deserialize)] + pub struct StringExample { + #[serde(with = "crate::serde::str_option")] + value: Option<Decimal>, + } + + let original = StringExample { + value: Some(Decimal::from_str("123.400").unwrap()), + }; + assert_eq!(&serde_json::to_string(&original).unwrap(), r#"{"value":"123.400"}"#); + let deserialized: StringExample = serde_json::from_str(r#"{"value":"123.400"}"#).unwrap(); + assert_eq!(deserialized.value, original.value); + assert!(deserialized.value.is_some()); + assert_eq!(deserialized.value.unwrap().unpack(), original.value.unwrap().unpack()); + + // Null tests + let original = StringExample { value: None }; + assert_eq!(&serde_json::to_string(&original).unwrap(), r#"{"value":null}"#); + let deserialized: StringExample = serde_json::from_str(r#"{"value":null}"#).unwrap(); + assert_eq!(deserialized.value, original.value); + assert!(deserialized.value.is_none()); + } + + #[test] + #[cfg(feature = "serde-with-float")] + fn with_float_optional() { + #[derive(Serialize, Deserialize)] + pub struct StringExample { + #[serde(with = "crate::serde::float_option")] + value: Option<Decimal>, + } + + let original = StringExample { + value: Some(Decimal::from_str("123.400").unwrap()), + }; + assert_eq!(&serde_json::to_string(&original).unwrap(), r#"{"value":123.4}"#); + let deserialized: StringExample = serde_json::from_str(r#"{"value":123.4}"#).unwrap(); + assert_eq!(deserialized.value, original.value); + assert!(deserialized.value.is_some()); // Scale is different! + + // Null tests + let original = StringExample { value: None }; + assert_eq!(&serde_json::to_string(&original).unwrap(), r#"{"value":null}"#); + let deserialized: StringExample = serde_json::from_str(r#"{"value":null}"#).unwrap(); + assert_eq!(deserialized.value, original.value); + assert!(deserialized.value.is_none()); + } + + #[test] + #[cfg(feature = "serde-with-arbitrary-precision")] + fn with_arbitrary_precision_optional() { + #[derive(Serialize, Deserialize)] + pub struct StringExample { + #[serde(with = "crate::serde::arbitrary_precision_option")] + value: Option<Decimal>, + } + + let original = StringExample { + value: Some(Decimal::from_str("123.400").unwrap()), + }; + assert_eq!(&serde_json::to_string(&original).unwrap(), r#"{"value":123.400}"#); + let deserialized: StringExample = serde_json::from_str(r#"{"value":123.400}"#).unwrap(); + assert_eq!(deserialized.value, original.value); + assert!(deserialized.value.is_some()); + assert_eq!(deserialized.value.unwrap().unpack(), original.value.unwrap().unpack()); + + // Null tests + let original = StringExample { value: None }; + assert_eq!(&serde_json::to_string(&original).unwrap(), r#"{"value":null}"#); + let deserialized: StringExample = serde_json::from_str(r#"{"value":null}"#).unwrap(); + assert_eq!(deserialized.value, original.value); + assert!(deserialized.value.is_none()); + } +} |