11use std:: fmt;
22use std:: hash:: { Hash , Hasher } ;
33
4- use num_bigint:: { BigInt , ToBigInt } ;
4+ use num_bigint:: BigInt ;
55use num_integer:: Integer ;
66use num_traits:: { Pow , Signed , ToPrimitive , Zero } ;
77
88use crate :: format:: FormatSpec ;
9- use crate :: function:: OptionalArg ;
9+ use crate :: function:: { OptionalArg , PyFuncArgs } ;
1010use crate :: pyobject:: {
1111 IntoPyObject , PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult , PyValue , TryFromObject ,
1212 TypeProtocol ,
@@ -510,11 +510,8 @@ fn int_new(cls: PyClassRef, options: IntOptions, vm: &VirtualMachine) -> PyResul
510510}
511511
512512// Casting function:
513- // TODO: this should just call `__int__` on the object
514513pub fn to_int ( vm : & VirtualMachine , obj : & PyObjectRef , base : u32 ) -> PyResult < BigInt > {
515514 match_class ! ( obj. clone( ) ,
516- i @ PyInt => Ok ( i. as_bigint( ) . clone( ) ) ,
517- f @ PyFloat => Ok ( f. to_f64( ) . to_bigint( ) . unwrap( ) ) ,
518515 s @ PyString => {
519516 i32 :: from_str_radix( s. as_str( ) , base)
520517 . map( BigInt :: from)
@@ -523,10 +520,21 @@ pub fn to_int(vm: &VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult<Big
523520 base, s
524521 ) ) )
525522 } ,
526- obj => Err ( vm. new_type_error( format!(
527- "int() argument must be a string or a number, not '{}'" ,
528- obj. class( ) . name
529- ) ) )
523+ obj => {
524+ if let Ok ( f) = vm. get_method( obj. clone( ) , "__int__" ) {
525+ let int_res = vm. invoke( f, PyFuncArgs :: default ( ) ) ?;
526+ match int_res. payload:: <PyInt >( ) {
527+ Some ( i) => Ok ( i. as_bigint( ) . clone( ) ) ,
528+ None => Err ( vm. new_type_error( format!(
529+ "TypeError: __int__ returned non-int (type '{}')" , int_res. class( ) . name) ) ) ,
530+ }
531+ } else {
532+ Err ( vm. new_type_error( format!(
533+ "int() argument must be a string or a number, not '{}'" ,
534+ obj. class( ) . name
535+ ) ) )
536+ }
537+ }
530538 )
531539}
532540
0 commit comments