forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.rs
More file actions
129 lines (117 loc) · 3.81 KB
/
utils.rs
File metadata and controls
129 lines (117 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::{
builtins::{PyFloat, PyStr},
function::{IntoPyException, IntoPyObject},
PyObject, PyObjectRef, PyObjectWrap, PyResult, TryFromObject, TypeProtocol, VirtualMachine,
};
use num_traits::ToPrimitive;
pub enum Either<A, B> {
A(A),
B(B),
}
impl<A: AsRef<PyObject>, B: AsRef<PyObject>> AsRef<PyObject> for Either<A, B> {
fn as_ref(&self) -> &PyObject {
match self {
Either::A(a) => a.as_ref(),
Either::B(b) => b.as_ref(),
}
}
}
impl<A: PyObjectWrap, B: PyObjectWrap> PyObjectWrap for Either<A, B> {
fn into_object(self) -> PyObjectRef {
match self {
Either::A(a) => a.into_object(),
Either::B(b) => b.into_object(),
}
}
}
impl<A: IntoPyObject, B: IntoPyObject> IntoPyObject for Either<A, B> {
fn into_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
match self {
Self::A(a) => a.into_pyobject(vm),
Self::B(b) => b.into_pyobject(vm),
}
}
}
/// This allows a builtin method to accept arguments that may be one of two
/// types, raising a `TypeError` if it is neither.
///
/// # Example
///
/// ```
/// use rustpython_vm::VirtualMachine;
/// use rustpython_vm::builtins::{PyStrRef, PyIntRef};
/// use rustpython_vm::utils::Either;
///
/// fn do_something(arg: Either<PyIntRef, PyStrRef>, vm: &VirtualMachine) {
/// match arg {
/// Either::A(int)=> {
/// // do something with int
/// }
/// Either::B(string) => {
/// // do something with string
/// }
/// }
/// }
/// ```
impl<A, B> TryFromObject for Either<A, B>
where
A: TryFromObject,
B: TryFromObject,
{
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
A::try_from_object(vm, obj.clone())
.map(Either::A)
.or_else(|_| B::try_from_object(vm, obj.clone()).map(Either::B))
.map_err(|_| vm.new_type_error(format!("unexpected type {}", obj.class())))
}
}
pub fn hash_iter<'a, I: IntoIterator<Item = &'a PyObjectRef>>(
iter: I,
vm: &VirtualMachine,
) -> PyResult<rustpython_common::hash::PyHash> {
vm.state.hash_secret.hash_iter(iter, |obj| obj.hash(vm))
}
pub fn hash_iter_unordered<'a, I: IntoIterator<Item = &'a PyObjectRef>>(
iter: I,
vm: &VirtualMachine,
) -> PyResult<rustpython_common::hash::PyHash> {
rustpython_common::hash::hash_iter_unordered(iter, |obj| obj.hash(vm))
}
// TODO: find a better place to put this impl
impl TryFromObject for std::time::Duration {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
use std::time::Duration;
if let Some(float) = obj.payload::<PyFloat>() {
Ok(Duration::from_secs_f64(float.to_f64()))
} else if let Some(int) = vm.to_index_opt(obj.clone()) {
let sec = int?
.as_bigint()
.to_u64()
.ok_or_else(|| vm.new_value_error("value out of range".to_owned()))?;
Ok(Duration::from_secs(sec))
} else {
Err(vm.new_type_error(format!(
"expected an int or float for duration, got {}",
obj.class()
)))
}
}
}
impl IntoPyObject for std::convert::Infallible {
fn into_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
match self {}
}
}
pub trait ToCString {
fn to_cstring(&self, vm: &VirtualMachine) -> PyResult<std::ffi::CString>;
}
impl ToCString for &str {
fn to_cstring(&self, vm: &VirtualMachine) -> PyResult<std::ffi::CString> {
std::ffi::CString::new(*self).map_err(|err| err.into_pyexception(vm))
}
}
impl ToCString for PyStr {
fn to_cstring(&self, vm: &VirtualMachine) -> PyResult<std::ffi::CString> {
std::ffi::CString::new(self.as_ref()).map_err(|err| err.into_pyexception(vm))
}
}