11pub ( crate ) use _testinternalcapi:: module_def;
22
3+ mod pytime;
4+
35use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
46
57static RARE_SET_CLASS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
@@ -26,6 +28,7 @@ pub(crate) fn note_func_modification() {
2628
2729#[ pymodule]
2830mod _testinternalcapi {
31+ use super :: pytime:: Round ;
2932 use super :: * ;
3033 use crate :: {
3134 AsObject , Py , PyObject , PyObjectRef , PyPayload , PyRef , PyResult , VirtualMachine ,
@@ -581,29 +584,96 @@ mod _testinternalcapi {
581584 #[ pyfunction( name = "_PyTime_AsTimeval_clamp" ) ]
582585 fn pytime_as_timeval_clamp ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < ( i64 , i64 ) > {
583586 let [ ns, round] = pytime_args :: < 2 > ( & args, "_PyTime_AsTimeval_clamp" , vm) ?;
584- let round = pytime_c_int ( round, vm) ?;
585- if !( 0 ..=3 ) . contains ( & round) {
586- return Err ( vm. new_value_error ( "invalid rounding" ) ) ;
587- }
587+ let round = Round :: from_int ( pytime_c_int ( round, vm) ?, vm) ?;
588588 // Validate rounding before converting the timestamp, as the C wrapper does.
589- let ns = pytime_i64 ( ns, vm) ?;
590- let quotient = ns / 1_000 ;
591- let remainder = ns % 1_000 ;
592- let round_away = match round {
593- 0 => remainder < 0 ,
594- 1 => remainder > 0 ,
595- 2 => remainder. abs ( ) > 500 || ( remainder. abs ( ) == 500 && quotient % 2 != 0 ) ,
596- _ => remainder != 0 ,
597- } ;
598- // Adjust the quotient, never ns: both signed 64-bit endpoints are valid.
599- let us = quotient + if round_away { ns. signum ( ) } else { 0 } ;
589+ pytime_timeval ( pytime_i64 ( ns, vm) ?, round, true , vm)
590+ }
591+
592+ fn pytime_timeval (
593+ ns : i64 ,
594+ round : Round ,
595+ clamp : bool ,
596+ vm : & VirtualMachine ,
597+ ) -> PyResult < ( i64 , i64 ) > {
598+ let us = round. divide ( ns, 1_000 ) ;
600599 // Windows timeval uses C long even though the host time_t is 64-bit.
601600 #[ cfg( windows) ]
602601 let ( minimum, maximum) : ( i64 , i64 ) =
603602 ( core:: ffi:: c_long:: MIN as _ , core:: ffi:: c_long:: MAX as _ ) ;
604603 #[ cfg( not( windows) ) ]
605604 let ( minimum, maximum) : ( i64 , i64 ) = ( TimeT :: MIN as _ , TimeT :: MAX as _ ) ;
606- pytime_pair ( us, 1_000_000 , minimum, maximum, true , vm)
605+ pytime_pair ( us, 1_000_000 , minimum, maximum, clamp, vm)
606+ }
607+
608+ #[ pyfunction( name = "_PyTime_FromSeconds" ) ]
609+ fn pytime_from_seconds ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < i64 > {
610+ let [ seconds] = pytime_args :: < 1 > ( & args, "_PyTime_FromSeconds" , vm) ?;
611+ Ok ( pytime:: from_seconds ( pytime_c_int ( seconds, vm) ?) )
612+ }
613+
614+ #[ pyfunction( name = "_PyTime_FromSecondsObject" ) ]
615+ fn pytime_from_seconds_object ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < i64 > {
616+ let [ object, round] = pytime_args :: < 2 > ( & args, "_PyTime_FromSecondsObject" , vm) ?;
617+ let round = Round :: from_int ( pytime_c_int ( round, vm) ?, vm) ?;
618+ pytime:: from_seconds_object ( object, round, vm)
619+ }
620+
621+ #[ pyfunction( name = "_PyTime_AsTimeval" ) ]
622+ fn pytime_as_timeval ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < ( i64 , i64 ) > {
623+ let [ ns, round] = pytime_args :: < 2 > ( & args, "_PyTime_AsTimeval" , vm) ?;
624+ let round = Round :: from_int ( pytime_c_int ( round, vm) ?, vm) ?;
625+ pytime_timeval ( pytime_i64 ( ns, vm) ?, round, false , vm)
626+ }
627+
628+ fn pytime_as_subseconds (
629+ args : FuncArgs ,
630+ name : & str ,
631+ divisor : i64 ,
632+ vm : & VirtualMachine ,
633+ ) -> PyResult < i64 > {
634+ let [ ns, round] = pytime_args :: < 2 > ( & args, name, vm) ?;
635+ let round = pytime_c_int ( round, vm) ?;
636+ // These two C wrappers convert the timestamp before validating the mode.
637+ let ns = pytime_i64 ( ns, vm) ?;
638+ Ok ( Round :: from_int ( round, vm) ?. divide ( ns, divisor) )
639+ }
640+
641+ #[ pyfunction( name = "_PyTime_AsMilliseconds" ) ]
642+ fn pytime_as_milliseconds ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < i64 > {
643+ pytime_as_subseconds ( args, "_PyTime_AsMilliseconds" , 1_000_000 , vm)
644+ }
645+
646+ #[ pyfunction( name = "_PyTime_AsMicroseconds" ) ]
647+ fn pytime_as_microseconds ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < i64 > {
648+ pytime_as_subseconds ( args, "_PyTime_AsMicroseconds" , 1_000 , vm)
649+ }
650+
651+ #[ pyfunction( name = "_PyTime_ObjectToTime_t" ) ]
652+ fn pytime_object_to_time_t ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < i64 > {
653+ let [ object, round] = pytime_args :: < 2 > ( & args, "_PyTime_ObjectToTime_t" , vm) ?;
654+ let round = Round :: from_int ( pytime_c_int ( round, vm) ?, vm) ?;
655+ pytime:: object_to_time_t ( object, round, vm)
656+ }
657+
658+ fn pytime_object_to_denominator (
659+ args : FuncArgs ,
660+ name : & str ,
661+ denominator : i64 ,
662+ vm : & VirtualMachine ,
663+ ) -> PyResult < ( i64 , i64 ) > {
664+ let [ object, round] = pytime_args :: < 2 > ( & args, name, vm) ?;
665+ let round = Round :: from_int ( pytime_c_int ( round, vm) ?, vm) ?;
666+ pytime:: object_to_denominator ( object, denominator, round, vm)
667+ }
668+
669+ #[ pyfunction( name = "_PyTime_ObjectToTimeval" ) ]
670+ fn pytime_object_to_timeval ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < ( i64 , i64 ) > {
671+ pytime_object_to_denominator ( args, "_PyTime_ObjectToTimeval" , 1_000_000 , vm)
672+ }
673+
674+ #[ pyfunction( name = "_PyTime_ObjectToTimespec" ) ]
675+ fn pytime_object_to_timespec ( args : FuncArgs , vm : & VirtualMachine ) -> PyResult < ( i64 , i64 ) > {
676+ pytime_object_to_denominator ( args, "_PyTime_ObjectToTimespec" , 1_000_000_000 , vm)
607677 }
608678
609679 #[ pyfunction]
0 commit comments