Skip to content

Commit 47cf683

Browse files
committed
Introduce TimeoutSeconds utility type for timeout parameters
Follow-up refactoring from #7237. Python timeout parameters typically accept both float and int. Several places in the codebase used Either<f64, i64> for this, each repeating the same match-and-convert boilerplate. This extracts that into a TimeoutSeconds type in vm::function::number. Refactored sites: - _sqlite3::ConnectArgs.timeout - _thread::AcquireArgs.timeout - _thread::ThreadHandle::join timeout Either<f64, i64> in time.rs (6 sites) left unchanged: those are timestamp values with per-branch logic (floor, range checks, etc). Either<f64, isize> in select.rs also left unchanged (different type).
1 parent cc4a7bb commit 47cf683

File tree

4 files changed

+46
-19
lines changed

4 files changed

+46
-19
lines changed

crates/stdlib/src/_sqlite3.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ mod _sqlite3 {
6161
},
6262
convert::IntoObject,
6363
function::{
64-
ArgCallable, ArgIterable, Either, FsPath, FuncArgs, OptionalArg, PyComparisonValue,
65-
PySetterValue,
64+
ArgCallable, ArgIterable, FsPath, FuncArgs, OptionalArg, PyComparisonValue,
65+
PySetterValue, TimeoutSeconds,
6666
},
6767
object::{Traverse, TraverseFn},
6868
protocol::{
@@ -333,8 +333,8 @@ mod _sqlite3 {
333333
struct ConnectArgs {
334334
#[pyarg(any)]
335335
database: FsPath,
336-
#[pyarg(any, default = Either::A(5.0))]
337-
timeout: Either<f64, i64>,
336+
#[pyarg(any, default = TimeoutSeconds::new(5.0))]
337+
timeout: TimeoutSeconds,
338338
#[pyarg(any, default = 0)]
339339
detect_types: c_int,
340340
#[pyarg(any, default = Some(vm.ctx.empty_str.to_owned()))]
@@ -991,10 +991,7 @@ mod _sqlite3 {
991991
fn initialize_db(args: &ConnectArgs, vm: &VirtualMachine) -> PyResult<Sqlite> {
992992
let path = args.database.to_cstring(vm)?;
993993
let db = Sqlite::from(SqliteRaw::open(path.as_ptr(), args.uri, vm)?);
994-
let timeout = (match args.timeout {
995-
Either::A(float) => float,
996-
Either::B(int) => int as f64,
997-
} * 1000.0) as c_int;
994+
let timeout = (args.timeout.to_secs_f64() * 1000.0) as c_int;
998995
db.busy_timeout(timeout);
999996
if let Some(isolation_level) = &args.isolation_level {
1000997
begin_statement_ptr_from_isolation_level(isolation_level, vm)?;

crates/vm/src/function/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ pub use fspath::FsPath;
2121
pub use getset::PySetterValue;
2222
pub(super) use getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetterFunc, PySetterFunc};
2323
pub use method::{HeapMethodDef, PyMethodDef, PyMethodFlags};
24-
pub use number::{ArgIndex, ArgIntoBool, ArgIntoComplex, ArgIntoFloat, ArgPrimitiveIndex, ArgSize};
24+
pub use number::{
25+
ArgIndex, ArgIntoBool, ArgIntoComplex, ArgIntoFloat, ArgPrimitiveIndex, ArgSize, TimeoutSeconds,
26+
};
2527
pub use protocol::{ArgCallable, ArgIterable, ArgMapping, ArgSequence};
2628

2729
use crate::{PyObject, PyResult, VirtualMachine, builtins::PyStr, convert::TryFromBorrowedObject};

crates/vm/src/function/number.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,32 @@ impl From<ArgSize> for isize {
196196
arg.value
197197
}
198198
}
199+
200+
/// A Python timeout value that accepts both `float` and `int`.
201+
///
202+
/// `TimeoutSeconds` implements `FromArgs` so that a built-in function can accept
203+
/// timeout parameters given as either `float` or `int`, normalizing them to `f64`.
204+
#[derive(Debug, Clone, Copy, PartialEq)]
205+
pub struct TimeoutSeconds {
206+
value: f64,
207+
}
208+
209+
impl TimeoutSeconds {
210+
pub const fn new(secs: f64) -> Self {
211+
Self { value: secs }
212+
}
213+
214+
#[inline]
215+
pub fn to_secs_f64(self) -> f64 {
216+
self.value
217+
}
218+
}
219+
220+
impl TryFromObject for TimeoutSeconds {
221+
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
222+
super::Either::<f64, i64>::try_from_object(vm, obj).map(|e| match e {
223+
super::Either::A(f) => Self { value: f },
224+
super::Either::B(i) => Self { value: i as f64 },
225+
})
226+
}
227+
}

crates/vm/src/stdlib/thread.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub(crate) mod _thread {
1515
builtins::{PyDictRef, PyStr, PyTupleRef, PyType, PyTypeRef, PyUtf8StrRef},
1616
common::wtf8::Wtf8Buf,
1717
frame::FrameRef,
18-
function::{ArgCallable, Either, FuncArgs, KwArgs, OptionalArg, PySetterValue},
18+
function::{ArgCallable, FuncArgs, KwArgs, OptionalArg, PySetterValue, TimeoutSeconds},
1919
types::{Constructor, GetAttr, Representable, SetAttr},
2020
};
2121
use alloc::{
@@ -65,17 +65,14 @@ pub(crate) mod _thread {
6565
struct AcquireArgs {
6666
#[pyarg(any, default = true)]
6767
blocking: bool,
68-
#[pyarg(any, default = Either::A(-1.0))]
69-
timeout: Either<f64, i64>,
68+
#[pyarg(any, default = TimeoutSeconds::new(-1.0))]
69+
timeout: TimeoutSeconds,
7070
}
7171

7272
macro_rules! acquire_lock_impl {
7373
($mu:expr, $args:expr, $vm:expr) => {{
7474
let (mu, args, vm) = ($mu, $args, $vm);
75-
let timeout = match args.timeout {
76-
Either::A(f) => f,
77-
Either::B(i) => i as f64,
78-
};
75+
let timeout = args.timeout.to_secs_f64();
7976
match args.blocking {
8077
true if timeout == -1.0 => {
8178
mu.lock();
@@ -1092,13 +1089,15 @@ pub(crate) mod _thread {
10921089
#[pymethod]
10931090
fn join(
10941091
&self,
1095-
timeout: OptionalArg<Option<Either<f64, i64>>>,
1092+
timeout: OptionalArg<Option<TimeoutSeconds>>,
10961093
vm: &VirtualMachine,
10971094
) -> PyResult<()> {
10981095
// Convert timeout to Duration (None or negative = infinite wait)
10991096
let timeout_duration = match timeout.flatten() {
1100-
Some(Either::A(t)) if t >= 0.0 => Some(Duration::from_secs_f64(t)),
1101-
Some(Either::B(t)) if t >= 0 => Some(Duration::from_secs(t as u64)),
1097+
Some(t) => {
1098+
let secs = t.to_secs_f64();
1099+
(secs >= 0.0).then(|| Duration::from_secs_f64(secs))
1100+
}
11021101
_ => None,
11031102
};
11041103

0 commit comments

Comments
 (0)