forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtry_from.rs
More file actions
124 lines (113 loc) · 3.84 KB
/
try_from.rs
File metadata and controls
124 lines (113 loc) · 3.84 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
use crate::{
builtins::PyFloat,
object::{AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult},
vm::VirtualMachine,
};
use num_traits::ToPrimitive;
/// Implemented by any type that can be created from a Python object.
///
/// Any type that implements `TryFromObject` is automatically `FromArgs`, and
/// so can be accepted as a argument to a built-in function.
pub trait TryFromObject: Sized {
/// Attempt to convert a Python object to a value of this type.
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self>;
}
/// Rust-side only version of TryFromObject to reduce unnecessary Rc::clone
impl<T: TryFromBorrowedObject> TryFromObject for T {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
TryFromBorrowedObject::try_from_borrowed_object(vm, &obj)
}
}
impl PyObjectRef {
pub fn try_into_value<T>(self, vm: &VirtualMachine) -> PyResult<T>
where
T: TryFromObject,
{
T::try_from_object(vm, self)
}
}
impl PyObject {
pub fn try_to_value<T>(&self, vm: &VirtualMachine) -> PyResult<T>
where
T: TryFromBorrowedObject,
{
T::try_from_borrowed_object(vm, self)
}
pub fn try_value_with<T, F, R>(&self, f: F, vm: &VirtualMachine) -> PyResult<R>
where
T: PyPayload,
F: Fn(&T) -> PyResult<R>,
{
let class = T::class(vm);
let special;
let py_ref = if self.fast_isinstance(class) {
self.downcast_ref()
.ok_or_else(|| vm.new_downcast_runtime_error(class, self))?
} else {
special = T::special_retrieve(vm, self)
.unwrap_or_else(|| Err(vm.new_downcast_type_error(class, self)))?;
&special
};
f(py_ref)
}
}
/// Lower-cost variation of `TryFromObject`
pub trait TryFromBorrowedObject: Sized {
/// Attempt to convert a Python object to a value of this type.
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self>;
}
impl<T> TryFromObject for PyRef<T>
where
T: PyPayload,
{
#[inline]
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let class = T::class(vm);
if obj.fast_isinstance(class) {
obj.downcast()
.map_err(|obj| vm.new_downcast_runtime_error(class, &obj))
} else {
T::special_retrieve(vm, &obj)
.unwrap_or_else(|| Err(vm.new_downcast_type_error(class, &obj)))
}
}
}
impl TryFromObject for PyObjectRef {
#[inline]
fn try_from_object(_vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
Ok(obj)
}
}
impl<T: TryFromObject> TryFromObject for Option<T> {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
if vm.is_none(&obj) {
Ok(None)
} else {
T::try_from_object(vm, obj).map(Some)
}
}
}
impl<T: TryFromObject> TryFromBorrowedObject for Vec<T> {
fn try_from_borrowed_object(vm: &VirtualMachine, value: &PyObject) -> PyResult<Self> {
vm.extract_elements_with(value, |obj| T::try_from_object(vm, obj))
}
}
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) = obj.try_index_opt(vm) {
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()
)))
}
}
}