@@ -24,6 +24,8 @@ use hashes::sha256d;
2424use internals:: compact_size;
2525#[ cfg( feature = "hex" ) ]
2626use internals:: write_err;
27+ #[ cfg( feature = "serde" ) ]
28+ use serde:: { de, Deserialize , Deserializer , Serialize , Serializer } ;
2729#[ cfg( feature = "hex" ) ]
2830use 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
363363impl 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]
@@ -770,4 +884,67 @@ mod tests {
770884 let version = Version ( 123 ) ;
771885 assert_eq ! ( format!( "{}" , version) , "123" ) ;
772886 }
887+
888+ // Creates an arbitrary dummy outpoint.
889+ #[ cfg( feature = "serde" ) ]
890+ fn tc_out_point ( ) -> OutPoint {
891+ let s = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20:1" ;
892+ s. parse :: < OutPoint > ( ) . unwrap ( )
893+ }
894+
895+ #[ test]
896+ #[ cfg( feature = "serde" ) ]
897+ fn out_point_serde_deserialize_human_readable ( ) {
898+ // `sered` serialization is the same as `Display` but includes quotes.
899+ let ser = "\" 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20:1\" " ;
900+ let got = serde_json:: from_str :: < OutPoint > ( ser) . unwrap ( ) ;
901+ let want = tc_out_point ( ) ;
902+
903+ assert_eq ! ( got, want) ;
904+ }
905+
906+ #[ test]
907+ #[ cfg( feature = "serde" ) ]
908+ fn out_point_serde_deserialize_non_human_readable ( ) {
909+ #[ rustfmt:: skip]
910+ let bytes = [
911+ // Length, pre-pended by the `serde` infrastructure because we use
912+ // slice serialization instead of array even though we know the length.
913+ 32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
914+ // The txid bytes
915+ 32 , 31 , 30 , 29 , 28 , 27 , 26 , 25 ,
916+ 24 , 23 , 22 , 21 , 20 , 19 , 18 , 17 ,
917+ 16 , 15 , 14 , 13 , 12 , 11 , 10 , 9 ,
918+ 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ,
919+ // The vout
920+ 1 , 0 , 0 , 0
921+ ] ;
922+
923+ let got = bincode:: deserialize :: < OutPoint > ( & bytes) . unwrap ( ) ;
924+ let want = tc_out_point ( ) ;
925+
926+ assert_eq ! ( got, want) ;
927+ }
928+
929+ #[ test]
930+ #[ cfg( feature = "serde" ) ]
931+ fn out_point_serde_human_readable_rountrips ( ) {
932+ let out_point = tc_out_point ( ) ;
933+
934+ let ser = serde_json:: to_string ( & out_point) . unwrap ( ) ;
935+ let got = serde_json:: from_str :: < OutPoint > ( & ser) . unwrap ( ) ;
936+
937+ assert_eq ! ( got, out_point) ;
938+ }
939+
940+ #[ test]
941+ #[ cfg( feature = "serde" ) ]
942+ fn out_point_serde_non_human_readable_rountrips ( ) {
943+ let out_point = tc_out_point ( ) ;
944+
945+ let ser = bincode:: serialize ( & out_point) . unwrap ( ) ;
946+ let got = bincode:: deserialize :: < OutPoint > ( & ser) . unwrap ( ) ;
947+
948+ assert_eq ! ( got, out_point) ;
949+ }
773950}
0 commit comments