Skip to content

Commit 711acaa

Browse files
committed
Support getset deleter
1 parent 9087c2f commit 711acaa

6 files changed

Lines changed: 193 additions & 151 deletions

File tree

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ libc = "0.2.126"
5252
nix = "0.23.1"
5353
paste = "1.0.7"
5454
is-macro = "0.2.0"
55-
result-like = "0.4.2"
55+
result-like ="0.4.4"
5656
num_enum = "0.5.7"
5757
bstr = "0.2.17"
5858
crossbeam-utils = "0.8.8"

vm/src/builtins/getset.rs

Lines changed: 2 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -4,153 +4,11 @@
44
use super::PyType;
55
use crate::{
66
class::PyClassImpl,
7-
convert::ToPyResult,
8-
function::{OwnedParam, RefParam},
9-
object::PyThreadingConstraint,
7+
function::{IntoPyGetterFunc, IntoPySetterFunc, PyGetterFunc, PySetterFunc},
108
types::{Constructor, GetDescriptor, Unconstructible},
119
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
1210
};
1311

14-
pub type PyGetterFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult)>;
15-
pub type PySetterFunc =
16-
Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult<()>)>;
17-
18-
pub trait IntoPyGetterFunc<T>: PyThreadingConstraint + Sized + 'static {
19-
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult;
20-
fn into_getter(self) -> PyGetterFunc {
21-
Box::new(move |vm, obj| self.get(obj, vm))
22-
}
23-
}
24-
25-
impl<F, T, R> IntoPyGetterFunc<(OwnedParam<T>, R, VirtualMachine)> for F
26-
where
27-
F: Fn(T, &VirtualMachine) -> R + 'static + Send + Sync,
28-
T: TryFromObject,
29-
R: ToPyResult,
30-
{
31-
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
32-
let obj = T::try_from_object(vm, obj)?;
33-
(self)(obj, vm).to_pyresult(vm)
34-
}
35-
}
36-
37-
impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R, VirtualMachine)> for F
38-
where
39-
F: Fn(&S, &VirtualMachine) -> R + 'static + Send + Sync,
40-
S: PyPayload,
41-
R: ToPyResult,
42-
{
43-
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
44-
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
45-
(self)(&zelf, vm).to_pyresult(vm)
46-
}
47-
}
48-
49-
impl<F, T, R> IntoPyGetterFunc<(OwnedParam<T>, R)> for F
50-
where
51-
F: Fn(T) -> R + 'static + Send + Sync,
52-
T: TryFromObject,
53-
R: ToPyResult,
54-
{
55-
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
56-
let obj = T::try_from_object(vm, obj)?;
57-
(self)(obj).to_pyresult(vm)
58-
}
59-
}
60-
61-
impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R)> for F
62-
where
63-
F: Fn(&S) -> R + 'static + Send + Sync,
64-
S: PyPayload,
65-
R: ToPyResult,
66-
{
67-
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
68-
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
69-
(self)(&zelf).to_pyresult(vm)
70-
}
71-
}
72-
73-
pub trait IntoPyNoResult {
74-
fn into_noresult(self) -> PyResult<()>;
75-
}
76-
77-
impl IntoPyNoResult for () {
78-
#[inline]
79-
fn into_noresult(self) -> PyResult<()> {
80-
Ok(())
81-
}
82-
}
83-
84-
impl IntoPyNoResult for PyResult<()> {
85-
#[inline]
86-
fn into_noresult(self) -> PyResult<()> {
87-
self
88-
}
89-
}
90-
91-
pub trait IntoPySetterFunc<T>: PyThreadingConstraint + Sized + 'static {
92-
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()>;
93-
fn into_setter(self) -> PySetterFunc {
94-
Box::new(move |vm, obj, value| self.set(obj, value, vm))
95-
}
96-
}
97-
98-
impl<F, T, V, R> IntoPySetterFunc<(OwnedParam<T>, V, R, VirtualMachine)> for F
99-
where
100-
F: Fn(T, V, &VirtualMachine) -> R + 'static + Send + Sync,
101-
T: TryFromObject,
102-
V: TryFromObject,
103-
R: IntoPyNoResult,
104-
{
105-
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
106-
let obj = T::try_from_object(vm, obj)?;
107-
let value = V::try_from_object(vm, value)?;
108-
(self)(obj, value, vm).into_noresult()
109-
}
110-
}
111-
112-
impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R, VirtualMachine)> for F
113-
where
114-
F: Fn(&S, V, &VirtualMachine) -> R + 'static + Send + Sync,
115-
S: PyPayload,
116-
V: TryFromObject,
117-
R: IntoPyNoResult,
118-
{
119-
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
120-
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
121-
let value = V::try_from_object(vm, value)?;
122-
(self)(&zelf, value, vm).into_noresult()
123-
}
124-
}
125-
126-
impl<F, T, V, R> IntoPySetterFunc<(OwnedParam<T>, V, R)> for F
127-
where
128-
F: Fn(T, V) -> R + 'static + Send + Sync,
129-
T: TryFromObject,
130-
V: TryFromObject,
131-
R: IntoPyNoResult,
132-
{
133-
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
134-
let obj = T::try_from_object(vm, obj)?;
135-
let value = V::try_from_object(vm, value)?;
136-
(self)(obj, value).into_noresult()
137-
}
138-
}
139-
140-
impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R)> for F
141-
where
142-
F: Fn(&S, V) -> R + 'static + Send + Sync,
143-
S: PyPayload,
144-
V: TryFromObject,
145-
R: IntoPyNoResult,
146-
{
147-
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
148-
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
149-
let value = V::try_from_object(vm, value)?;
150-
(self)(&zelf, value).into_noresult()
151-
}
152-
}
153-
15412
#[pyclass(module = false, name = "getset_descriptor")]
15513
pub struct PyGetSet {
15614
name: String,
@@ -249,7 +107,7 @@ impl PyGetSet {
249107
) -> PyResult<()> {
250108
let zelf = PyRef::<Self>::try_from_object(vm, zelf)?;
251109
if let Some(ref f) = zelf.setter {
252-
f(vm, obj, value.unwrap_or_else(|| vm.ctx.none()))
110+
f(vm, obj, value.into())
253111
} else {
254112
Err(vm.new_attribute_error(format!(
255113
"attribute '{}' of '{}' objects is not writable",

vm/src/function/getset.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*! Python `attribute` descriptor class. (PyGetSet)
2+
3+
*/
4+
use crate::{
5+
convert::ToPyResult,
6+
function::{OwnedParam, RefParam},
7+
object::PyThreadingConstraint,
8+
PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
9+
};
10+
11+
#[derive(result_like::OptionLike)]
12+
pub enum PySetterValue<T = PyObjectRef> {
13+
Assign(T),
14+
Delete,
15+
}
16+
17+
trait FromPySetterValue
18+
where
19+
Self: Sized,
20+
{
21+
fn from_setter_value(vm: &VirtualMachine, obj: PySetterValue) -> PyResult<Self>;
22+
}
23+
24+
impl<T> FromPySetterValue for T
25+
where
26+
T: Sized + TryFromObject,
27+
{
28+
fn from_setter_value(vm: &VirtualMachine, obj: PySetterValue) -> PyResult<Self> {
29+
let obj = obj.ok_or_else(|| vm.new_type_error("can't delete attribute".to_owned()))?;
30+
T::try_from_object(vm, obj)
31+
}
32+
}
33+
34+
impl<T> FromPySetterValue for PySetterValue<T>
35+
where
36+
T: Sized + TryFromObject,
37+
{
38+
fn from_setter_value(vm: &VirtualMachine, obj: PySetterValue) -> PyResult<Self> {
39+
Ok(obj.map(|obj| T::try_from_object(vm, obj)).transpose()?)
40+
}
41+
}
42+
43+
pub type PyGetterFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult)>;
44+
pub type PySetterFunc =
45+
Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyObjectRef, PySetterValue) -> PyResult<()>)>;
46+
47+
pub trait IntoPyGetterFunc<T>: PyThreadingConstraint + Sized + 'static {
48+
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult;
49+
fn into_getter(self) -> PyGetterFunc {
50+
Box::new(move |vm, obj| self.get(obj, vm))
51+
}
52+
}
53+
54+
impl<F, T, R> IntoPyGetterFunc<(OwnedParam<T>, R, VirtualMachine)> for F
55+
where
56+
F: Fn(T, &VirtualMachine) -> R + 'static + Send + Sync,
57+
T: TryFromObject,
58+
R: ToPyResult,
59+
{
60+
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
61+
let obj = T::try_from_object(vm, obj)?;
62+
(self)(obj, vm).to_pyresult(vm)
63+
}
64+
}
65+
66+
impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R, VirtualMachine)> for F
67+
where
68+
F: Fn(&S, &VirtualMachine) -> R + 'static + Send + Sync,
69+
S: PyPayload,
70+
R: ToPyResult,
71+
{
72+
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
73+
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
74+
(self)(&zelf, vm).to_pyresult(vm)
75+
}
76+
}
77+
78+
impl<F, T, R> IntoPyGetterFunc<(OwnedParam<T>, R)> for F
79+
where
80+
F: Fn(T) -> R + 'static + Send + Sync,
81+
T: TryFromObject,
82+
R: ToPyResult,
83+
{
84+
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
85+
let obj = T::try_from_object(vm, obj)?;
86+
(self)(obj).to_pyresult(vm)
87+
}
88+
}
89+
90+
impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R)> for F
91+
where
92+
F: Fn(&S) -> R + 'static + Send + Sync,
93+
S: PyPayload,
94+
R: ToPyResult,
95+
{
96+
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
97+
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
98+
(self)(&zelf).to_pyresult(vm)
99+
}
100+
}
101+
102+
pub trait IntoPyNoResult {
103+
fn into_noresult(self) -> PyResult<()>;
104+
}
105+
106+
impl IntoPyNoResult for () {
107+
#[inline]
108+
fn into_noresult(self) -> PyResult<()> {
109+
Ok(())
110+
}
111+
}
112+
113+
impl IntoPyNoResult for PyResult<()> {
114+
#[inline]
115+
fn into_noresult(self) -> PyResult<()> {
116+
self
117+
}
118+
}
119+
120+
pub trait IntoPySetterFunc<T>: PyThreadingConstraint + Sized + 'static {
121+
fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()>;
122+
fn into_setter(self) -> PySetterFunc {
123+
Box::new(move |vm, obj, value| self.set(obj, value, vm))
124+
}
125+
}
126+
127+
impl<F, T, V, R> IntoPySetterFunc<(OwnedParam<T>, V, R, VirtualMachine)> for F
128+
where
129+
F: Fn(T, V, &VirtualMachine) -> R + 'static + Send + Sync,
130+
T: TryFromObject,
131+
V: FromPySetterValue,
132+
R: IntoPyNoResult,
133+
{
134+
fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
135+
let obj = T::try_from_object(vm, obj)?;
136+
let value = V::from_setter_value(vm, value)?;
137+
(self)(obj, value, vm).into_noresult()
138+
}
139+
}
140+
141+
impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R, VirtualMachine)> for F
142+
where
143+
F: Fn(&S, V, &VirtualMachine) -> R + 'static + Send + Sync,
144+
S: PyPayload,
145+
V: FromPySetterValue,
146+
R: IntoPyNoResult,
147+
{
148+
fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
149+
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
150+
let value = V::from_setter_value(vm, value)?;
151+
(self)(&zelf, value, vm).into_noresult()
152+
}
153+
}
154+
155+
impl<F, T, V, R> IntoPySetterFunc<(OwnedParam<T>, V, R)> for F
156+
where
157+
F: Fn(T, V) -> R + 'static + Send + Sync,
158+
T: TryFromObject,
159+
V: FromPySetterValue,
160+
R: IntoPyNoResult,
161+
{
162+
fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
163+
let obj = T::try_from_object(vm, obj)?;
164+
let value = V::from_setter_value(vm, value)?;
165+
(self)(obj, value).into_noresult()
166+
}
167+
}
168+
169+
impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R)> for F
170+
where
171+
F: Fn(&S, V) -> R + 'static + Send + Sync,
172+
S: PyPayload,
173+
V: FromPySetterValue,
174+
R: IntoPyNoResult,
175+
{
176+
fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
177+
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
178+
let value = V::from_setter_value(vm, value)?;
179+
(self)(&zelf, value).into_noresult()
180+
}
181+
}

vm/src/function/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod arithmetic;
33
mod buffer;
44
mod builtin;
55
mod either;
6+
mod getset;
67
mod number;
78
mod protocol;
89

@@ -14,6 +15,8 @@ pub use arithmetic::{PyArithmeticValue, PyComparisonValue};
1415
pub use buffer::{ArgAsciiBuffer, ArgBytesLike, ArgMemoryBuffer, ArgStrOrBytesLike};
1516
pub use builtin::{IntoPyNativeFunc, OwnedParam, PyNativeFunc, RefParam};
1617
pub use either::Either;
18+
pub use getset::PySetterValue;
19+
pub(super) use getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetterFunc, PySetterFunc};
1720
pub use number::{ArgIntoBool, ArgIntoComplex, ArgIntoFloat};
1821
pub use protocol::{ArgCallable, ArgIterable, ArgMapping, ArgSequence};
1922

0 commit comments

Comments
 (0)