Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions crates/vm/src/stdlib/_testinternalcapi.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
pub(crate) use _testinternalcapi::module_def;

mod pytime;

use core::sync::atomic::{AtomicUsize, Ordering};

static RARE_SET_CLASS: AtomicUsize = AtomicUsize::new(0);
Expand All @@ -28,7 +26,6 @@ pub(crate) fn note_func_modification() {

#[pymodule]
mod _testinternalcapi {
use super::pytime::Round;
use super::*;
use crate::{
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
Expand All @@ -43,6 +40,7 @@ mod _testinternalcapi {
function::{FuncArgs, OptionalArg, PyComparisonValue},
object::{Traverse, TraverseFn},
protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
stdlib::time::pytime::{self, Round},
types::{
AsMapping, AsSequence, Comparable, IterNext, Iterable, PyComparisonOp, PyTypeFlags,
SelfIter,
Expand Down
44 changes: 5 additions & 39 deletions crates/vm/src/stdlib/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// https://docs.python.org/3/library/time.html

pub use decl::time;
pub(crate) mod pytime;

pub(crate) use decl::module_def;
pub(crate) use decl::perf_counter_ns as profiler_time;
Expand All @@ -19,7 +20,7 @@ mod decl {
use crate::convert::{ToPyException, ToPyObject};
use crate::{
AsObject, Py, PyObjectRef, PyResult, VirtualMachine,
builtins::{PyFloat, PyStr, PyStrRef, PyTypeRef},
builtins::{PyStr, PyStrRef, PyTypeRef},
class::PyClassDef,
common::wtf8::Wtf8Buf,
function::{Either, FuncArgs, OptionalArg, OptionalOption},
Expand All @@ -33,7 +34,6 @@ mod decl {
use core::time::Duration;
#[cfg(not(any(unix, windows)))]
use jiff::{Timestamp, Zoned, civil::DateTime, tz::TimeZone};
use num_traits::ToPrimitive;
#[cfg(target_os = "wasi")]
use rustpython_host_env::time::ClockId;
#[cfg(any(unix, windows))]
Expand Down Expand Up @@ -128,43 +128,9 @@ mod decl {
fn sleep(object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
vm.audit("time.sleep", || (object.clone(),))?;

let overflow = || vm.new_overflow_error("timestamp out of range for C PyTime_t");
let nanoseconds = if object.number().is_index() {
let seconds = object.try_index(vm).map_err(|e| {
if e.fast_isinstance(vm.ctx.exceptions.overflow_error) {
overflow()
} else {
e
}
})?;
seconds
.as_bigint()
.to_i64()
.and_then(|seconds| seconds.checked_mul(SEC_TO_NS))
.ok_or_else(overflow)?
} else {
// PyFloat_AsDouble reads float subclasses without calling __float__.
let seconds = match object.downcast_ref::<PyFloat>() {
Some(value) => value.to_f64(),
None => object.try_float(vm)?.to_f64(),
};
if seconds.is_nan() {
return Err(vm.new_value_error("Invalid value NaN (not a number)"));
}
// _PyTime_ROUND_TIMEOUT rounds away from zero.
let nanoseconds = seconds * SEC_TO_NS as f64;
let nanoseconds = if nanoseconds >= 0.0 {
nanoseconds.ceil()
} else {
nanoseconds.floor()
};
let minimum = i64::MIN as f64;
// The signed maximum rounds up to 2**63 as a double.
if !(minimum..-minimum).contains(&nanoseconds) {
return Err(overflow());
}
nanoseconds as i64
};
// _PyTime_ROUND_TIMEOUT rounds away from zero.
let nanoseconds =
super::pytime::from_seconds_object(&object, super::pytime::Round::Up, vm)?;
if nanoseconds < 0 {
return Err(vm.new_value_error("sleep length must be non-negative"));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Numeric conversions used by the internal PyTime test helpers.
//! Signed nanosecond timestamps and the rounding used by Python's time APIs.

#![cfg_attr(target_env = "musl", allow(deprecated))]

Expand All @@ -7,25 +7,25 @@ use num_traits::ToPrimitive;
use rustpython_host_env::time::SEC_TO_NS;

#[cfg(any(unix, windows))]
pub(super) use rustpython_host_env::time::TimeT;
pub(crate) use rustpython_host_env::time::TimeT;
#[cfg(not(any(unix, windows)))]
pub(super) type TimeT = i64;
pub(crate) type TimeT = i64;

const TIME_T_MIN: i64 = TimeT::MIN as _;
const TIME_T_MAX: i64 = TimeT::MAX as _;
const PYTIME_OVERFLOW: &str = "timestamp out of range for C PyTime_t";
const TIME_T_OVERFLOW: &str = "timestamp out of range for platform time_t";

#[derive(Clone, Copy)]
pub(super) enum Round {
pub(crate) enum Round {
Floor,
Ceiling,
HalfEven,
Up,
}

impl Round {
pub(super) fn from_int(value: i32, vm: &VirtualMachine) -> PyResult<Self> {
pub(crate) fn from_int(value: i32, vm: &VirtualMachine) -> PyResult<Self> {
match value {
0 => Ok(Self::Floor),
1 => Ok(Self::Ceiling),
Expand All @@ -45,7 +45,7 @@ impl Round {
}
}

pub(super) fn divide(self, value: i64, divisor: i64) -> i64 {
pub(crate) fn divide(self, value: i64, divisor: i64) -> i64 {
debug_assert!(divisor > 1);
let quotient = value / divisor;
let remainder = value % divisor;
Expand All @@ -65,7 +65,7 @@ impl Round {
}
}

pub(super) fn from_seconds(seconds: i32) -> i64 {
pub(crate) fn from_seconds(seconds: i32) -> i64 {
i64::from(seconds) * SEC_TO_NS
}

Expand Down Expand Up @@ -95,7 +95,7 @@ fn float_seconds(object: &PyObject, vm: &VirtualMachine) -> PyResult<f64> {
Ok(seconds)
}

pub(super) fn from_seconds_object(
pub(crate) fn from_seconds_object(
object: &PyObject,
round: Round,
vm: &VirtualMachine,
Expand Down Expand Up @@ -132,7 +132,7 @@ fn float_to_time_t(seconds: f64, vm: &VirtualMachine) -> PyResult<i64> {
Ok(seconds as i64)
}

pub(super) fn object_to_time_t(
pub(crate) fn object_to_time_t(
object: &PyObject,
round: Round,
vm: &VirtualMachine,
Expand All @@ -144,7 +144,7 @@ pub(super) fn object_to_time_t(
}
}

pub(super) fn object_to_denominator(
pub(crate) fn object_to_denominator(
object: &PyObject,
denominator: i64,
round: Round,
Expand Down
Loading