@@ -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,28 @@ 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+ fn read_nint < R : BufRead + Seek > ( raw : & mut Deserializer < R > ) -> Result < i128 , DeserializeError > {
586+ let found = raw. cbor_type ( ) ?;
587+ if found != cbor_event:: Type :: NegativeInteger {
588+ return Err ( cbor_event:: Error :: Expected ( cbor_event:: Type :: NegativeInteger , found) . into ( ) ) ;
589+ }
590+ let ( len, len_sz) = raw. cbor_len ( ) ?;
591+ match len {
592+ cbor_event:: Len :: Indefinite => Err ( cbor_event:: Error :: IndefiniteLenNotSupported ( cbor_event:: Type :: NegativeInteger ) . into ( ) ) ,
593+ cbor_event:: Len :: Len ( v) => {
594+ raw. advance ( 1 + len_sz) ?;
595+ Ok ( -( v as i128 ) - 1 )
596+ }
597+ }
598+ }
599+
583600const BOUNDED_BYTES_CHUNK_SIZE : usize = 64 ;
584601
585602pub ( crate ) fn write_bounded_bytes < ' se , W : Write > ( serializer : & ' se mut Serializer < W > , bytes : & [ u8 ] ) -> cbor_event:: Result < & ' se mut Serializer < W > > {
@@ -706,22 +723,28 @@ impl cbor_event::se::Serialize for BigInt {
706723 num_bigint:: Sign :: Minus => serializer. write_negative_integer ( -( * u64_digits. first ( ) . unwrap ( ) as i128 ) as i64 ) ,
707724 } ,
708725 _ => {
726+ // Small edge case: nint's minimum is -18446744073709551616 but in this bigint lib
727+ // that takes 2 u64 bytes so we put that as a special case here:
728+ if sign == num_bigint:: Sign :: Minus && u64_digits == vec ! [ 0 , 1 ] {
729+ serializer. write_negative_integer ( -18446744073709551616i128 as i64 )
730+ } else {
709731 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- } ,
732+ match sign {
733+ // positive bigint
734+ num_bigint:: Sign :: Plus |
735+ num_bigint:: Sign :: NoSign => {
736+ serializer. write_tag ( 2u64 ) ?;
737+ write_bounded_bytes ( serializer, & bytes)
738+ } ,
739+ // negative bigint
740+ num_bigint:: Sign :: Minus => {
741+ serializer. write_tag ( 3u64 ) ?;
742+ use std:: ops:: Neg ;
743+ // CBOR RFC defines this as the bytes of -n -1
744+ let adjusted = self . 0 . clone ( ) . neg ( ) . checked_sub ( & num_bigint:: BigInt :: from ( 1u32 ) ) . unwrap ( ) . to_biguint ( ) . unwrap ( ) ;
745+ write_bounded_bytes ( serializer, & adjusted. to_bytes_be ( ) )
746+ } ,
747+ }
725748 }
726749 } ,
727750 }
@@ -753,7 +776,7 @@ impl Deserialize for BigInt {
753776 // uint
754777 CBORType :: UnsignedInteger => Ok ( Self ( num_bigint:: BigInt :: from ( raw. unsigned_integer ( ) ?) ) ) ,
755778 // nint
756- CBORType :: NegativeInteger => Ok ( Self ( num_bigint:: BigInt :: from ( raw . negative_integer ( ) ?) ) ) ,
779+ CBORType :: NegativeInteger => Ok ( Self ( num_bigint:: BigInt :: from ( read_nint ( raw ) ?) ) ) ,
757780 _ => return Err ( DeserializeFailure :: NoVariantMatched . into ( ) ) ,
758781 }
759782 } ) ( ) . map_err ( |e| e. annotate ( "BigInt" ) )
@@ -2085,9 +2108,8 @@ mod tests {
20852108 assert_eq ! ( hex:: decode( "c249010000000000000000" ) . unwrap( ) , BigInt :: from_str( "18446744073709551616" ) . unwrap( ) . to_bytes( ) ) ;
20862109 // uint
20872110 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());
2111+ // nint (lowest possible - used to be unsupported but works now)
2112+ assert_eq ! ( hex:: decode( "3bffffffffffffffff" ) . unwrap( ) , BigInt :: from_str( "-18446744073709551616" ) . unwrap( ) . to_bytes( ) ) ;
20912113 // this one fits in an i64 though
20922114 assert_eq ! ( hex:: decode( "3903e7" ) . unwrap( ) , BigInt :: from_str( "-1000" ) . unwrap( ) . to_bytes( ) ) ;
20932115
@@ -2299,4 +2321,22 @@ mod tests {
22992321 assert_eq ! ( Int :: new_i32( 42 ) . as_i32_or_fail( ) . unwrap( ) , 42 ) ;
23002322 assert_eq ! ( Int :: new_i32( -42 ) . as_i32_or_fail( ) . unwrap( ) , -42 ) ;
23012323 }
2324+
2325+ #[ test]
2326+ fn int_full_range ( ) {
2327+ // cbor_event's nint API worked via i64 but we now have a workaround for it
2328+ // so these tests are here to make sure that workaround works.
2329+
2330+ // first nint below of i64::MIN
2331+ let bytes_x = vec ! [ 0x3b , 0x80 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ] ;
2332+ let x = Int :: from_bytes ( bytes_x. clone ( ) ) . unwrap ( ) ;
2333+ assert_eq ! ( x. to_str( ) , "-9223372036854775809" ) ;
2334+ assert_eq ! ( bytes_x, x. to_bytes( ) ) ;
2335+
2336+ // smallest possible nint which is -u64::MAX - 1
2337+ let bytes_y = vec ! [ 0x3b , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ] ;
2338+ let y = Int :: from_bytes ( bytes_y. clone ( ) ) . unwrap ( ) ;
2339+ assert_eq ! ( y. to_str( ) , "-18446744073709551616" ) ;
2340+ assert_eq ! ( bytes_y, y. to_bytes( ) ) ;
2341+ }
23022342}
0 commit comments