@@ -17,6 +17,7 @@ use bstr::ByteSlice;
1717use num_bigint:: { BigInt , BigUint , Sign } ;
1818use num_integer:: Integer ;
1919use num_traits:: { One , Pow , PrimInt , Signed , ToPrimitive , Zero } ;
20+ use std:: borrow:: Cow ;
2021use std:: fmt;
2122
2223/// int(x=0) -> integer
@@ -263,7 +264,10 @@ impl Constructor for PyInt {
263264 val
264265 } ;
265266
266- try_int ( & val, vm)
267+ // try_int(&val, vm)
268+ PyNumber :: from ( val. as_ref ( ) )
269+ . int ( vm)
270+ . map ( |x| x. as_bigint ( ) . clone ( ) )
267271 }
268272 } else if let OptionalArg :: Present ( _) = options. base {
269273 Err ( vm. new_type_error ( "int() missing string argument" . to_owned ( ) ) )
@@ -346,7 +350,7 @@ impl PyInt {
346350 }
347351}
348352
349- #[ pyimpl( flags( BASETYPE ) , with( Comparable , Hashable , Constructor ) ) ]
353+ #[ pyimpl( flags( BASETYPE ) , with( Comparable , Hashable , Constructor , AsNumber ) ) ]
350354impl PyInt {
351355 #[ pymethod( name = "__radd__" ) ]
352356 #[ pymethod( magic) ]
@@ -751,6 +755,114 @@ impl Hashable for PyInt {
751755 }
752756}
753757
758+ impl AsNumber for PyInt {
759+ fn as_number ( _zelf : & crate :: Py < Self > , _vm : & VirtualMachine ) -> Cow < ' static , PyNumberMethods > {
760+ Cow :: Borrowed ( & Self :: NUMBER_METHODS )
761+ }
762+ }
763+
764+ impl PyInt {
765+ fn number_protocol_binop < F > (
766+ number : & PyNumber ,
767+ other : & PyObject ,
768+ op : & str ,
769+ f : F ,
770+ vm : & VirtualMachine ,
771+ ) -> PyResult
772+ where
773+ F : FnOnce ( & BigInt , & BigInt ) -> BigInt ,
774+ {
775+ let ( a, b) = Self :: downcast_or_binop_error ( number, other, op, vm) ?;
776+ let ret = f ( & a. value , & b. value ) ;
777+ Ok ( vm. ctx . new_int ( ret) . into ( ) )
778+ }
779+
780+ fn number_protocol_int ( number : & PyNumber , vm : & VirtualMachine ) -> PyIntRef {
781+ if let Some ( zelf) = number. obj . downcast_ref_if_exact :: < Self > ( vm) {
782+ zelf. to_owned ( )
783+ } else {
784+ let zelf = Self :: number_downcast ( number) ;
785+ vm. ctx . new_int ( zelf. value . clone ( ) )
786+ }
787+ }
788+
789+ const NUMBER_METHODS : PyNumberMethods = PyNumberMethods {
790+ add : Some ( |number, other, vm| {
791+ Self :: number_protocol_binop ( number, other, "+" , |a, b| a + b, vm)
792+ } ) ,
793+ subtract : Some ( |number, other, vm| {
794+ Self :: number_protocol_binop ( number, other, "-" , |a, b| a - b, vm)
795+ } ) ,
796+ multiply : Some ( |number, other, vm| {
797+ Self :: number_protocol_binop ( number, other, "*" , |a, b| a * b, vm)
798+ } ) ,
799+ remainder : Some ( |number, other, vm| {
800+ let ( a, b) = Self :: downcast_or_binop_error ( number, other, "%" , vm) ?;
801+ inner_mod ( & a. value , & b. value , vm)
802+ } ) ,
803+ divmod : Some ( |number, other, vm| {
804+ let ( a, b) = Self :: downcast_or_binop_error ( number, other, "divmod()" , vm) ?;
805+ inner_divmod ( & a. value , & b. value , vm)
806+ } ) ,
807+ power : Some ( |number, other, vm| {
808+ let ( a, b) = Self :: downcast_or_binop_error ( number, other, "** or pow()" , vm) ?;
809+ inner_pow ( & a. value , & b. value , vm)
810+ } ) ,
811+ negative : Some ( |number, vm| {
812+ let zelf = Self :: number_downcast ( number) ;
813+ Ok ( vm. ctx . new_int ( -& zelf. value ) . into ( ) )
814+ } ) ,
815+ positive : Some ( |number, vm| Ok ( Self :: number_protocol_int ( number, vm) . into ( ) ) ) ,
816+ absolute : Some ( |number, vm| {
817+ let zelf = Self :: number_downcast ( number) ;
818+ Ok ( vm. ctx . new_int ( zelf. value . abs ( ) ) . into ( ) )
819+ } ) ,
820+ boolean : Some ( |number, _vm| {
821+ let zelf = Self :: number_downcast ( number) ;
822+ Ok ( zelf. value . is_zero ( ) )
823+ } ) ,
824+ invert : Some ( |number, vm| {
825+ let zelf = Self :: number_downcast ( number) ;
826+ Ok ( vm. ctx . new_int ( !& zelf. value ) . into ( ) )
827+ } ) ,
828+ lshift : Some ( |number, other, vm| {
829+ let ( a, b) = Self :: downcast_or_binop_error ( number, other, "<<" , vm) ?;
830+ inner_lshift ( & a. value , & b. value , vm)
831+ } ) ,
832+ rshift : Some ( |number, other, vm| {
833+ let ( a, b) = Self :: downcast_or_binop_error ( number, other, ">>" , vm) ?;
834+ inner_rshift ( & a. value , & b. value , vm)
835+ } ) ,
836+ and : Some ( |number, other, vm| {
837+ Self :: number_protocol_binop ( number, other, "&" , |a, b| a & b, vm)
838+ } ) ,
839+ xor : Some ( |number, other, vm| {
840+ Self :: number_protocol_binop ( number, other, "^" , |a, b| a ^ b, vm)
841+ } ) ,
842+ or : Some ( |number, other, vm| {
843+ Self :: number_protocol_binop ( number, other, "|" , |a, b| a | b, vm)
844+ } ) ,
845+ int : Some ( |number, other| Ok ( Self :: number_protocol_int ( number, other) ) ) ,
846+ float : Some ( |number, vm| {
847+ let zelf = number
848+ . obj
849+ . downcast_ref :: < Self > ( )
850+ . ok_or_else ( || vm. new_type_error ( "an integer is required" . to_owned ( ) ) ) ?;
851+ try_to_float ( & zelf. value , vm) . map ( |x| vm. ctx . new_float ( x) )
852+ } ) ,
853+ floor_divide : Some ( |number, other, vm| {
854+ let ( a, b) = Self :: downcast_or_binop_error ( number, other, "//" , vm) ?;
855+ inner_floordiv ( & a. value , & b. value , vm)
856+ } ) ,
857+ true_divide : Some ( |number, other, vm| {
858+ let ( a, b) = Self :: downcast_or_binop_error ( number, other, "/" , vm) ?;
859+ inner_truediv ( & a. value , & b. value , vm)
860+ } ) ,
861+ index : Some ( |number, vm| Ok ( Self :: number_protocol_int ( number, vm) ) ) ,
862+ ..* PyNumberMethods :: not_implemented ( )
863+ } ;
864+ }
865+
754866#[ derive( FromArgs ) ]
755867pub struct IntOptions {
756868 #[ pyarg( positional, optional) ]
@@ -926,65 +1038,6 @@ fn i2f(int: &BigInt) -> Option<f64> {
9261038 int. to_f64 ( ) . filter ( |f| f. is_finite ( ) )
9271039}
9281040
929- pub ( crate ) fn try_int ( obj : & PyObject , vm : & VirtualMachine ) -> PyResult < BigInt > {
930- fn try_convert ( obj : & PyObject , lit : & [ u8 ] , vm : & VirtualMachine ) -> PyResult < BigInt > {
931- let base = 10 ;
932- match bytes_to_int ( lit, base) {
933- Some ( i) => Ok ( i) ,
934- None => Err ( vm. new_value_error ( format ! (
935- "invalid literal for int() with base {}: {}" ,
936- base,
937- obj. repr( vm) ?,
938- ) ) ) ,
939- }
940- }
941-
942- // test for strings and bytes
943- if let Some ( s) = obj. downcast_ref :: < PyStr > ( ) {
944- return try_convert ( obj, s. as_str ( ) . as_bytes ( ) , vm) ;
945- }
946- if let Ok ( r) = obj. try_bytes_like ( vm, |x| try_convert ( obj, x, vm) ) {
947- return r;
948- }
949- // strict `int` check
950- if let Some ( int) = obj. payload_if_exact :: < PyInt > ( vm) {
951- return Ok ( int. as_bigint ( ) . clone ( ) ) ;
952- }
953- // call __int__, then __index__, then __trunc__ (converting the __trunc__ result via __index__ if needed)
954- // TODO: using __int__ is deprecated and removed in Python 3.10
955- if let Some ( method) = vm. get_method ( obj. to_owned ( ) , identifier ! ( vm, __int__) ) {
956- let result = vm. invoke ( & method?, ( ) ) ?;
957- return match result. payload :: < PyInt > ( ) {
958- Some ( int_obj) => Ok ( int_obj. as_bigint ( ) . clone ( ) ) ,
959- None => Err ( vm. new_type_error ( format ! (
960- "__int__ returned non-int (type '{}')" ,
961- result. class( ) . name( )
962- ) ) ) ,
963- } ;
964- }
965- // TODO: returning strict subclasses of int in __index__ is deprecated
966- if let Some ( r) = vm. to_index_opt ( obj. to_owned ( ) ) . transpose ( ) ? {
967- return Ok ( r. as_bigint ( ) . clone ( ) ) ;
968- }
969- if let Some ( method) = vm. get_method ( obj. to_owned ( ) , identifier ! ( vm, __trunc__) ) {
970- let result = vm. invoke ( & method?, ( ) ) ?;
971- return vm
972- . to_index_opt ( result. clone ( ) )
973- . unwrap_or_else ( || {
974- Err ( vm. new_type_error ( format ! (
975- "__trunc__ returned non-Integral (type {})" ,
976- result. class( ) . name( )
977- ) ) )
978- } )
979- . map ( |int_obj| int_obj. as_bigint ( ) . clone ( ) ) ;
980- }
981-
982- Err ( vm. new_type_error ( format ! (
983- "int() argument must be a string, a bytes-like object or a number, not '{}'" ,
984- obj. class( ) . name( )
985- ) ) )
986- }
987-
9881041pub ( crate ) fn init ( context : & Context ) {
9891042 PyInt :: extend_class ( context, context. types . int_type ) ;
9901043}
0 commit comments