@@ -479,6 +479,8 @@ impl Deserialize for Value {
479479#[ derive( Clone , Debug , Eq , Hash , Ord , PartialEq , PartialOrd ) ]
480480pub struct Int ( pub ( crate ) i128 ) ;
481481
482+ to_from_bytes ! ( Int ) ;
483+
482484#[ wasm_bindgen]
483485impl Int {
484486 pub fn new ( x : & BigNum ) -> Self {
@@ -573,13 +575,30 @@ impl Deserialize for Int {
573575 ( || -> Result < _ , DeserializeError > {
574576 match raw. cbor_type ( ) ? {
575577 cbor_event:: Type :: UnsignedInteger => Ok ( Self ( raw. unsigned_integer ( ) ? as i128 ) ) ,
576- cbor_event:: Type :: NegativeInteger => Ok ( Self ( raw . negative_integer ( ) ? as i128 ) ) ,
578+ cbor_event:: Type :: NegativeInteger => Ok ( Self ( read_nint ( raw ) ? ) ) ,
577579 _ => Err ( DeserializeFailure :: NoVariantMatched . into ( ) ) ,
578580 }
579581 } ) ( ) . map_err ( |e| e. annotate ( "Int" ) )
580582 }
581583}
582584
585+ /// TODO: this function can be removed in case `cbor_event` library ever gets a fix on their side
586+ /// See https://github.com/Emurgo/cardano-serialization-lib/pull/392
587+ fn read_nint < R : BufRead + Seek > ( raw : & mut Deserializer < R > ) -> Result < i128 , DeserializeError > {
588+ let found = raw. cbor_type ( ) ?;
589+ if found != cbor_event:: Type :: NegativeInteger {
590+ return Err ( cbor_event:: Error :: Expected ( cbor_event:: Type :: NegativeInteger , found) . into ( ) ) ;
591+ }
592+ let ( len, len_sz) = raw. cbor_len ( ) ?;
593+ match len {
594+ cbor_event:: Len :: Indefinite => Err ( cbor_event:: Error :: IndefiniteLenNotSupported ( cbor_event:: Type :: NegativeInteger ) . into ( ) ) ,
595+ cbor_event:: Len :: Len ( v) => {
596+ raw. advance ( 1 + len_sz) ?;
597+ Ok ( -( v as i128 ) - 1 )
598+ }
599+ }
600+ }
601+
583602const BOUNDED_BYTES_CHUNK_SIZE : usize = 64 ;
584603
585604pub ( crate ) fn write_bounded_bytes < ' se , W : Write > ( serializer : & ' se mut Serializer < W > , bytes : & [ u8 ] ) -> cbor_event:: Result < & ' se mut Serializer < W > > {
@@ -706,22 +725,28 @@ impl cbor_event::se::Serialize for BigInt {
706725 num_bigint:: Sign :: Minus => serializer. write_negative_integer ( -( * u64_digits. first ( ) . unwrap ( ) as i128 ) as i64 ) ,
707726 } ,
708727 _ => {
728+ // Small edge case: nint's minimum is -18446744073709551616 but in this bigint lib
729+ // that takes 2 u64 bytes so we put that as a special case here:
730+ if sign == num_bigint:: Sign :: Minus && u64_digits == vec ! [ 0 , 1 ] {
731+ serializer. write_negative_integer ( -18446744073709551616i128 as i64 )
732+ } else {
709733 let ( sign, bytes) = self . 0 . to_bytes_be ( ) ;
710- match sign {
711- // positive bigint
712- num_bigint:: Sign :: Plus |
713- num_bigint:: Sign :: NoSign => {
714- serializer. write_tag ( 2u64 ) ?;
715- write_bounded_bytes ( serializer, & bytes)
716- } ,
717- // negative bigint
718- num_bigint:: Sign :: Minus => {
719- serializer. write_tag ( 3u64 ) ?;
720- use std:: ops:: Neg ;
721- // CBOR RFC defines this as the bytes of -n -1
722- let adjusted = self . 0 . clone ( ) . neg ( ) . checked_sub ( & num_bigint:: BigInt :: from ( 1u32 ) ) . unwrap ( ) . to_biguint ( ) . unwrap ( ) ;
723- write_bounded_bytes ( serializer, & adjusted. to_bytes_be ( ) )
724- } ,
734+ match sign {
735+ // positive bigint
736+ num_bigint:: Sign :: Plus |
737+ num_bigint:: Sign :: NoSign => {
738+ serializer. write_tag ( 2u64 ) ?;
739+ write_bounded_bytes ( serializer, & bytes)
740+ } ,
741+ // negative bigint
742+ num_bigint:: Sign :: Minus => {
743+ serializer. write_tag ( 3u64 ) ?;
744+ use std:: ops:: Neg ;
745+ // CBOR RFC defines this as the bytes of -n -1
746+ let adjusted = self . 0 . clone ( ) . neg ( ) . checked_sub ( & num_bigint:: BigInt :: from ( 1u32 ) ) . unwrap ( ) . to_biguint ( ) . unwrap ( ) ;
747+ write_bounded_bytes ( serializer, & adjusted. to_bytes_be ( ) )
748+ } ,
749+ }
725750 }
726751 } ,
727752 }
@@ -753,7 +778,7 @@ impl Deserialize for BigInt {
753778 // uint
754779 CBORType :: UnsignedInteger => Ok ( Self ( num_bigint:: BigInt :: from ( raw. unsigned_integer ( ) ?) ) ) ,
755780 // nint
756- CBORType :: NegativeInteger => Ok ( Self ( num_bigint:: BigInt :: from ( raw . negative_integer ( ) ?) ) ) ,
781+ CBORType :: NegativeInteger => Ok ( Self ( num_bigint:: BigInt :: from ( read_nint ( raw ) ?) ) ) ,
757782 _ => return Err ( DeserializeFailure :: NoVariantMatched . into ( ) ) ,
758783 }
759784 } ) ( ) . map_err ( |e| e. annotate ( "BigInt" ) )
@@ -2085,9 +2110,8 @@ mod tests {
20852110 assert_eq ! ( hex:: decode( "c249010000000000000000" ) . unwrap( ) , BigInt :: from_str( "18446744073709551616" ) . unwrap( ) . to_bytes( ) ) ;
20862111 // uint
20872112 assert_eq ! ( hex:: decode( "1b000000e8d4a51000" ) . unwrap( ) , BigInt :: from_str( "1000000000000" ) . unwrap( ) . to_bytes( ) ) ;
2088- // nint
2089- // we can't use this due to cbor_event actually not supporting the full NINT spectrum as it uses an i64 for some reason...
2090- //assert_eq!(hex::decode("3bffffffffffffffff").unwrap(), BigInt::from_str("-18446744073709551616").unwrap().to_bytes());
2113+ // nint (lowest possible - used to be unsupported but works now)
2114+ assert_eq ! ( hex:: decode( "3bffffffffffffffff" ) . unwrap( ) , BigInt :: from_str( "-18446744073709551616" ) . unwrap( ) . to_bytes( ) ) ;
20912115 // this one fits in an i64 though
20922116 assert_eq ! ( hex:: decode( "3903e7" ) . unwrap( ) , BigInt :: from_str( "-1000" ) . unwrap( ) . to_bytes( ) ) ;
20932117
@@ -2299,4 +2323,22 @@ mod tests {
22992323 assert_eq ! ( Int :: new_i32( 42 ) . as_i32_or_fail( ) . unwrap( ) , 42 ) ;
23002324 assert_eq ! ( Int :: new_i32( -42 ) . as_i32_or_fail( ) . unwrap( ) , -42 ) ;
23012325 }
2326+
2327+ #[ test]
2328+ fn int_full_range ( ) {
2329+ // cbor_event's nint API worked via i64 but we now have a workaround for it
2330+ // so these tests are here to make sure that workaround works.
2331+
2332+ // first nint below of i64::MIN
2333+ let bytes_x = vec ! [ 0x3b , 0x80 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ] ;
2334+ let x = Int :: from_bytes ( bytes_x. clone ( ) ) . unwrap ( ) ;
2335+ assert_eq ! ( x. to_str( ) , "-9223372036854775809" ) ;
2336+ assert_eq ! ( bytes_x, x. to_bytes( ) ) ;
2337+
2338+ // smallest possible nint which is -u64::MAX - 1
2339+ let bytes_y = vec ! [ 0x3b , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ] ;
2340+ let y = Int :: from_bytes ( bytes_y. clone ( ) ) . unwrap ( ) ;
2341+ assert_eq ! ( y. to_str( ) , "-18446744073709551616" ) ;
2342+ assert_eq ! ( bytes_y, y. to_bytes( ) ) ;
2343+ }
23022344}
0 commit comments