forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathutils.rs
More file actions
128 lines (116 loc) · 3.74 KB
/
Copy pathutils.rs
File metadata and controls
128 lines (116 loc) · 3.74 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
use crate::{
builtins::{pystr::PyStr, PyFloat},
exceptions::IntoPyException,
IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
VirtualMachine,
};
use num_traits::ToPrimitive;
pub enum Either<A, B> {
A(A),
B(B),
}
impl<A: PyValue, B: PyValue> Either<PyRef<A>, PyRef<B>> {
pub fn as_object(&self) -> &PyObjectRef {
match self {
Either::A(a) => a.as_object(),
Either::B(b) => b.as_object(),
}
}
pub 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| vm._hash(obj))
}
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| vm._hash(obj))
}
// 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))
}
}