mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
add string_or_u64 serialization (#2698)
This commit is contained in:
parent
bd6824ca4c
commit
6949a0d341
2 changed files with 106 additions and 0 deletions
|
@ -159,9 +159,11 @@ pub struct TxKernel {
|
||||||
/// Options for a kernel's structure or use
|
/// Options for a kernel's structure or use
|
||||||
pub features: KernelFeatures,
|
pub features: KernelFeatures,
|
||||||
/// Fee originally included in the transaction this proof is for.
|
/// Fee originally included in the transaction this proof is for.
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
pub fee: u64,
|
pub fee: u64,
|
||||||
/// This kernel is not valid earlier than lock_height blocks
|
/// This kernel is not valid earlier than lock_height blocks
|
||||||
/// The max lock_height of all *inputs* to this transaction
|
/// The max lock_height of all *inputs* to this transaction
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
pub lock_height: u64,
|
pub lock_height: u64,
|
||||||
/// Remainder of the sum of all transaction commitments. If the transaction
|
/// Remainder of the sum of all transaction commitments. If the transaction
|
||||||
/// is well formed, amounts components should sum to zero and the excess
|
/// is well formed, amounts components should sum to zero and the excess
|
||||||
|
|
|
@ -164,6 +164,104 @@ where
|
||||||
serializer.serialize_str(&to_hex(bytes.as_ref().to_vec()))
|
serializer.serialize_str(&to_hex(bytes.as_ref().to_vec()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to ensure u64s are serialised in json
|
||||||
|
/// as strings by default, since it can't be guaranteed that consumers
|
||||||
|
/// will know what to do with u64 literals (e.g. Javascript). However,
|
||||||
|
/// fields using this tag can be deserialized from literals or strings.
|
||||||
|
/// From solutions on:
|
||||||
|
/// https://github.com/serde-rs/json/issues/329
|
||||||
|
pub mod string_or_u64 {
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::{de, Deserializer, Serializer};
|
||||||
|
|
||||||
|
/// serialize into a string
|
||||||
|
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
T: fmt::Display,
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.collect_str(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// deserialize from either literal or string
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct Visitor;
|
||||||
|
impl<'a> de::Visitor<'a> for Visitor {
|
||||||
|
type Value = u64;
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
formatter,
|
||||||
|
"a string containing digits or an int fitting into u64"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
s.parse().map_err(de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_any(Visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// As above, for Options
|
||||||
|
pub mod opt_string_or_u64 {
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use serde::{de, Deserializer, Serializer};
|
||||||
|
|
||||||
|
/// serialize into string or none
|
||||||
|
pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
T: fmt::Display,
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
Some(v) => serializer.collect_str(v),
|
||||||
|
None => serializer.serialize_none(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// deser from 'null', literal or string
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct Visitor;
|
||||||
|
impl<'a> de::Visitor<'a> for Visitor {
|
||||||
|
type Value = Option<u64>;
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
formatter,
|
||||||
|
"null, a string containing digits or an int fitting into u64"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn visit_unit<E>(self) -> Result<Self::Value, E> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
|
||||||
|
Ok(Some(v))
|
||||||
|
}
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let val: u64 = s.parse().map_err(de::Error::custom)?;
|
||||||
|
Ok(Some(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deserializer.deserialize_any(Visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test serialization methods of components that are being used
|
// Test serialization methods of components that are being used
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
@ -185,6 +283,10 @@ mod test {
|
||||||
pub opt_sig: Option<Signature>,
|
pub opt_sig: Option<Signature>,
|
||||||
#[serde(with = "sig_serde")]
|
#[serde(with = "sig_serde")]
|
||||||
pub sig: Signature,
|
pub sig: Signature,
|
||||||
|
#[serde(with = "string_or_u64")]
|
||||||
|
pub num: u64,
|
||||||
|
#[serde(with = "opt_string_or_u64")]
|
||||||
|
pub opt_num: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerTest {
|
impl SerTest {
|
||||||
|
@ -200,6 +302,8 @@ mod test {
|
||||||
pub_key: PublicKey::from_secret_key(&secp, &sk).unwrap(),
|
pub_key: PublicKey::from_secret_key(&secp, &sk).unwrap(),
|
||||||
opt_sig: Some(sig.clone()),
|
opt_sig: Some(sig.clone()),
|
||||||
sig: sig.clone(),
|
sig: sig.clone(),
|
||||||
|
num: 30,
|
||||||
|
opt_num: Some(33),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue