Skip to content

Commit

Permalink
primitives: add manual serde serialization for Outpoint
Browse files Browse the repository at this point in the history
Required downstream to allow correct string encoding for Outpoint in JSON/YAML/TOML and other text serialization formats
  • Loading branch information
dr-orlovsky committed Oct 7, 2023
1 parent 7403cd1 commit f5ea7c8
Showing 1 changed file with 62 additions and 1 deletion.
63 changes: 62 additions & 1 deletion primitives/src/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ impl FromStr for Vout {
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_BITCOIN)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]
#[display("{txid}:{vout}")]
pub struct Outpoint {
pub txid: Txid,
Expand Down Expand Up @@ -162,6 +161,68 @@ impl FromStr for Outpoint {
}
}

#[cfg(feature = "serde")]
mod _serde_outpoint {
use std::fmt;

use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeTuple;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use super::*;

impl Serialize for Outpoint {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
if serializer.is_human_readable() {
serializer.serialize_str(&self.to_string())
} else {
let mut ser = serializer.serialize_tuple(2)?;
ser.serialize_element(&self.txid)?;
ser.serialize_element(&self.vout)?;
ser.end()
}
}
}

impl<'de> Deserialize<'de> for Outpoint {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
use serde::de::Error;
if deserializer.is_human_readable() {
String::deserialize(deserializer).and_then(|string| {
Self::from_str(&string)
.map_err(|_| D::Error::custom("wrong outpoint string representation"))
})
} else {
struct OutpointVisitor;

impl<'de> Visitor<'de> for OutpointVisitor {
type Value = Outpoint;

fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "a transaction outpoint")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where A: SeqAccess<'de> {
let mut outpoint = Outpoint::coinbase();
outpoint.txid = seq
.next_element()?
.ok_or_else(|| Error::invalid_length(0, &self))?;
outpoint.vout = seq
.next_element()?
.ok_or_else(|| Error::invalid_length(1, &self))?;
Ok(outpoint)
}
}

deserializer.deserialize_tuple(2, OutpointVisitor)
}
}
}
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_BITCOIN)]
Expand Down

0 comments on commit f5ea7c8

Please sign in to comment.