Fix Optional Amount Serialization
This commit is contained in:
parent
c9c2e452e2
commit
da21294ac5
|
@ -880,6 +880,9 @@ pub mod serde {
|
||||||
fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
|
fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
|
||||||
fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
|
fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
|
||||||
fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
|
fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
|
||||||
|
fn type_prefix() -> &'static str;
|
||||||
|
fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
|
||||||
|
fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerdeAmount for Amount {
|
impl SerdeAmount for Amount {
|
||||||
|
@ -896,6 +899,15 @@ pub mod serde {
|
||||||
use serde::de::Error;
|
use serde::de::Error;
|
||||||
Ok(Amount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
|
Ok(Amount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
|
||||||
}
|
}
|
||||||
|
fn type_prefix() -> &'static str {
|
||||||
|
"u"
|
||||||
|
}
|
||||||
|
fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
s.serialize_some(&self.as_sat())
|
||||||
|
}
|
||||||
|
fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
s.serialize_some(&self.as_btc())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerdeAmount for SignedAmount {
|
impl SerdeAmount for SignedAmount {
|
||||||
|
@ -912,6 +924,15 @@ pub mod serde {
|
||||||
use serde::de::Error;
|
use serde::de::Error;
|
||||||
Ok(SignedAmount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
|
Ok(SignedAmount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
|
||||||
}
|
}
|
||||||
|
fn type_prefix() -> &'static str {
|
||||||
|
"i"
|
||||||
|
}
|
||||||
|
fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
s.serialize_some(&self.as_sat())
|
||||||
|
}
|
||||||
|
fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
s.serialize_some(&self.as_btc())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod as_sat {
|
pub mod as_sat {
|
||||||
|
@ -933,15 +954,17 @@ pub mod serde {
|
||||||
//! Serialize and deserialize [Optoin<Amount>] as real numbers denominated in satoshi.
|
//! Serialize and deserialize [Optoin<Amount>] as real numbers denominated in satoshi.
|
||||||
//! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`.
|
//! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`.
|
||||||
|
|
||||||
use serde::{Deserializer, Serializer};
|
use serde::{Deserializer, Serializer, de};
|
||||||
use util::amount::serde::SerdeAmount;
|
use util::amount::serde::SerdeAmount;
|
||||||
|
use std::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub fn serialize<A: SerdeAmount, S: Serializer>(
|
pub fn serialize<A: SerdeAmount, S: Serializer>(
|
||||||
a: &Option<A>,
|
a: &Option<A>,
|
||||||
s: S,
|
s: S,
|
||||||
) -> Result<S::Ok, S::Error> {
|
) -> Result<S::Ok, S::Error> {
|
||||||
match *a {
|
match *a {
|
||||||
Some(a) => a.ser_sat(s),
|
Some(a) => a.ser_sat_opt(s),
|
||||||
None => s.serialize_none(),
|
None => s.serialize_none(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -949,7 +972,28 @@ pub mod serde {
|
||||||
pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(
|
pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(
|
||||||
d: D,
|
d: D,
|
||||||
) -> Result<Option<A>, D::Error> {
|
) -> Result<Option<A>, D::Error> {
|
||||||
Ok(Some(A::des_sat(d)?))
|
struct VisitOptAmt<X>(PhantomData<X>);
|
||||||
|
|
||||||
|
impl<'de, X: SerdeAmount> de::Visitor<'de> for VisitOptAmt<X> {
|
||||||
|
type Value = Option<X>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(formatter, "An Option<{}64>", X::type_prefix())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_none<E>(self) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>
|
||||||
|
{
|
||||||
|
Ok(Some(X::des_sat(d)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.deserialize_option(VisitOptAmt::<A>(PhantomData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -973,15 +1017,17 @@ pub mod serde {
|
||||||
//! Serialize and deserialize [Option<Amount>] as JSON numbers denominated in BTC.
|
//! Serialize and deserialize [Option<Amount>] as JSON numbers denominated in BTC.
|
||||||
//! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`.
|
//! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`.
|
||||||
|
|
||||||
use serde::{Deserializer, Serializer};
|
use serde::{Deserializer, Serializer, de};
|
||||||
use util::amount::serde::SerdeAmount;
|
use util::amount::serde::SerdeAmount;
|
||||||
|
use std::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub fn serialize<A: SerdeAmount, S: Serializer>(
|
pub fn serialize<A: SerdeAmount, S: Serializer>(
|
||||||
a: &Option<A>,
|
a: &Option<A>,
|
||||||
s: S,
|
s: S,
|
||||||
) -> Result<S::Ok, S::Error> {
|
) -> Result<S::Ok, S::Error> {
|
||||||
match *a {
|
match *a {
|
||||||
Some(a) => a.ser_btc(s),
|
Some(a) => a.ser_btc_opt(s),
|
||||||
None => s.serialize_none(),
|
None => s.serialize_none(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -989,7 +1035,28 @@ pub mod serde {
|
||||||
pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(
|
pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(
|
||||||
d: D,
|
d: D,
|
||||||
) -> Result<Option<A>, D::Error> {
|
) -> Result<Option<A>, D::Error> {
|
||||||
Ok(Some(A::des_btc(d)?))
|
struct VisitOptAmt<X>(PhantomData<X>);
|
||||||
|
|
||||||
|
impl<'de, X :SerdeAmount> de::Visitor<'de> for VisitOptAmt<X> {
|
||||||
|
type Value = Option<X>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(formatter, "An Option<f64>")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_none<E>(self) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Ok(Some(X::des_btc(d)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.deserialize_option(VisitOptAmt::<A>(PhantomData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1345,7 +1412,7 @@ mod tests {
|
||||||
fn serde_as_btc_opt() {
|
fn serde_as_btc_opt() {
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Eq)]
|
||||||
struct T {
|
struct T {
|
||||||
#[serde(default, with = "::util::amount::serde::as_btc::opt")]
|
#[serde(default, with = "::util::amount::serde::as_btc::opt")]
|
||||||
pub amt: Option<Amount>,
|
pub amt: Option<Amount>,
|
||||||
|
@ -1362,6 +1429,13 @@ mod tests {
|
||||||
samt: None,
|
samt: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Test Roundtripping
|
||||||
|
for s in [&with, &without].iter() {
|
||||||
|
let v = serde_json::to_string(s).unwrap();
|
||||||
|
let w : T = serde_json::from_str(&v).unwrap();
|
||||||
|
assert_eq!(w, **s);
|
||||||
|
}
|
||||||
|
|
||||||
let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
|
let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
|
||||||
assert_eq!(t, with);
|
assert_eq!(t, with);
|
||||||
|
|
||||||
|
@ -1375,4 +1449,47 @@ mod tests {
|
||||||
let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
|
let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
|
||||||
assert_eq!(without, serde_json::from_value(value_without).unwrap());
|
assert_eq!(without, serde_json::from_value(value_without).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
#[test]
|
||||||
|
fn serde_as_sat_opt() {
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug, Eq)]
|
||||||
|
struct T {
|
||||||
|
#[serde(default, with = "::util::amount::serde::as_sat::opt")]
|
||||||
|
pub amt: Option<Amount>,
|
||||||
|
#[serde(default, with = "::util::amount::serde::as_sat::opt")]
|
||||||
|
pub samt: Option<SignedAmount>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let with = T {
|
||||||
|
amt: Some(Amount::from_sat(2__500_000_00)),
|
||||||
|
samt: Some(SignedAmount::from_sat(-2__500_000_00)),
|
||||||
|
};
|
||||||
|
let without = T {
|
||||||
|
amt: None,
|
||||||
|
samt: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test Roundtripping
|
||||||
|
for s in [&with, &without].iter() {
|
||||||
|
let v = serde_json::to_string(s).unwrap();
|
||||||
|
let w : T = serde_json::from_str(&v).unwrap();
|
||||||
|
assert_eq!(w, **s);
|
||||||
|
}
|
||||||
|
|
||||||
|
let t: T = serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap();
|
||||||
|
assert_eq!(t, with);
|
||||||
|
|
||||||
|
let t: T = serde_json::from_str("{}").unwrap();
|
||||||
|
assert_eq!(t, without);
|
||||||
|
|
||||||
|
let value_with: serde_json::Value =
|
||||||
|
serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap();
|
||||||
|
assert_eq!(with, serde_json::from_value(value_with).unwrap());
|
||||||
|
|
||||||
|
let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
|
||||||
|
assert_eq!(without, serde_json::from_value(value_without).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue