Skip to content

Commit 42d3039

Browse files
committed
Manually implement serde traits for OutPoint
Reading Rust macros makes my eyes bleed - the `internals::serde_struct_human_string_impl` is a great example. The macro is used in exactly one place, for `OutPoint`. Implement `serde` stuff for `OutPoint` and remove `serde_struct_human_string_impl` - death to all macros.
1 parent 0b0980b commit 42d3039

File tree

1 file changed

+116
-2
lines changed

1 file changed

+116
-2
lines changed

primitives/src/transaction.rs

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use hashes::sha256d;
2424
use internals::compact_size;
2525
#[cfg(feature = "hex")]
2626
use internals::write_err;
27+
#[cfg(feature = "serde")]
28+
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
2729
#[cfg(feature = "hex")]
2830
use units::parse_int;
2931

@@ -357,8 +359,6 @@ pub struct OutPoint {
357359
/// The index of the referenced output in its transaction's vout.
358360
pub vout: u32,
359361
}
360-
#[cfg(feature = "serde")]
361-
internals::serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout);
362362

363363
impl OutPoint {
364364
/// The number of bytes that an outpoint contributes to the size of a transaction.
@@ -419,6 +419,120 @@ fn parse_vout(s: &str) -> Result<u32, ParseOutPointError> {
419419
parse_int::int_from_str(s).map_err(ParseOutPointError::Vout)
420420
}
421421

422+
#[cfg(feature = "serde")]
423+
impl Serialize for OutPoint {
424+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
425+
where
426+
S: Serializer,
427+
{
428+
if serializer.is_human_readable() {
429+
serializer.collect_str(&self)
430+
} else {
431+
use crate::serde::ser::SerializeStruct as _;
432+
433+
let mut state = serializer.serialize_struct("OutPoint", 2)?;
434+
// serializing as an array was found in the past to break for some serializers so we use
435+
// a slice instead. This causes 8 bytes to be prepended for the length (even though this
436+
// is a bit silly because know the length).
437+
state.serialize_field("txid", self.txid.as_byte_array().as_slice())?;
438+
state.serialize_field("vout", &self.vout.to_le_bytes())?;
439+
state.end()
440+
}
441+
}
442+
}
443+
444+
#[cfg(feature = "serde")]
445+
impl<'de> Deserialize<'de> for OutPoint {
446+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
447+
where
448+
D: Deserializer<'de>,
449+
{
450+
if deserializer.is_human_readable() {
451+
struct StringVisitor;
452+
453+
impl<'de> de::Visitor<'de> for StringVisitor {
454+
type Value = OutPoint;
455+
456+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
457+
formatter.write_str("a string in format 'txid:vout'")
458+
}
459+
460+
fn visit_str<E>(self, value: &str) -> Result<OutPoint, E>
461+
where
462+
E: de::Error,
463+
{
464+
value.parse::<OutPoint>().map_err(de::Error::custom)
465+
}
466+
}
467+
468+
deserializer.deserialize_str(StringVisitor)
469+
} else {
470+
#[derive(Deserialize)]
471+
#[serde(field_identifier, rename_all = "lowercase")]
472+
enum Field {
473+
Txid,
474+
Vout,
475+
}
476+
477+
struct OutPointVisitor;
478+
479+
impl<'de> de::Visitor<'de> for OutPointVisitor {
480+
type Value = OutPoint;
481+
482+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
483+
formatter.write_str("OutPoint struct with fields")
484+
}
485+
486+
fn visit_seq<V>(self, mut seq: V) -> Result<OutPoint, V::Error>
487+
where
488+
V: de::SeqAccess<'de>,
489+
{
490+
let txid =
491+
seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
492+
let vout =
493+
seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
494+
Ok(OutPoint { txid, vout })
495+
}
496+
497+
fn visit_map<V>(self, mut map: V) -> Result<OutPoint, V::Error>
498+
where
499+
V: de::MapAccess<'de>,
500+
{
501+
let mut txid = None;
502+
let mut vout = None;
503+
504+
while let Some(key) = map.next_key()? {
505+
match key {
506+
Field::Txid => {
507+
if txid.is_some() {
508+
return Err(de::Error::duplicate_field("txid"));
509+
}
510+
let bytes: [u8; 32] = map.next_value()?;
511+
txid = Some(Txid::from_byte_array(bytes));
512+
}
513+
Field::Vout => {
514+
if vout.is_some() {
515+
return Err(de::Error::duplicate_field("vout"));
516+
}
517+
let bytes: [u8; 4] = map.next_value()?;
518+
vout = Some(u32::from_le_bytes(bytes));
519+
}
520+
}
521+
}
522+
523+
let txid = txid.ok_or_else(|| de::Error::missing_field("txid"))?;
524+
let vout = vout.ok_or_else(|| de::Error::missing_field("vout"))?;
525+
526+
Ok(OutPoint { txid, vout })
527+
}
528+
}
529+
530+
const FIELDS: &[&str] = &["txid", "vout"];
531+
deserializer.deserialize_struct("OutPoint", FIELDS, OutPointVisitor)
532+
}
533+
}
534+
}
535+
422536
/// An error in parsing an [`OutPoint`].
423537
#[derive(Debug, Clone, PartialEq, Eq)]
424538
#[non_exhaustive]

0 commit comments

Comments
 (0)