Skip to content
Prev Previous commit
Next Next commit
PySetResult and IntoPySetResult
  • Loading branch information
youknowone committed Feb 5, 2020
commit a5c7a699f0df94ea344af580a4e7b35f56df54b6
31 changes: 19 additions & 12 deletions vm/src/obj/objgetset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
use super::objtype::PyClassRef;
use crate::function::{OptionalArg, OwnedParam, RefParam};
use crate::pyobject::{
IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
IntoPyObject, IntoPySetResult, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult,
PySetResult, PyValue, TryFromObject,
};
use crate::slots::PyBuiltinDescriptor;
use crate::vm::VirtualMachine;

pub type PyGetterFunc = Box<dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult>;
pub type PySetterFunc = Box<dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult<()>>;
pub type PySetterFunc = Box<dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PySetResult>;

pub trait IntoPyGetterFunc<T, R> {
fn into_getter(self) -> PyGetterFunc;
Expand Down Expand Up @@ -44,36 +45,41 @@ where
}
}

pub trait IntoPySetterFunc<T, V> {
pub trait IntoPySetterFunc<T, V, R>
where
R: IntoPySetResult,
{
fn into_setter(self) -> PySetterFunc;
}

impl<F, T, V> IntoPySetterFunc<OwnedParam<T>, V> for F
impl<F, T, V, R> IntoPySetterFunc<OwnedParam<T>, V, R> for F
where
F: Fn(T, V, &VirtualMachine) -> PyResult<()> + 'static,
F: Fn(T, V, &VirtualMachine) -> R + 'static,
T: TryFromObject,
V: TryFromObject,
R: IntoPySetResult,
{
fn into_setter(self) -> PySetterFunc {
Box::new(move |vm, obj, value| {
let obj = T::try_from_object(vm, obj)?;
let value = V::try_from_object(vm, value)?;
(self)(obj, value, vm)
(self)(obj, value, vm).into_pysetresult()
})
}
}

impl<F, S, V> IntoPySetterFunc<RefParam<S>, V> for F
impl<F, S, V, R> IntoPySetterFunc<RefParam<S>, V, R> for F
where
F: Fn(&S, V, &VirtualMachine) -> PyResult<()> + 'static,
F: Fn(&S, V, &VirtualMachine) -> R + 'static,
S: PyValue,
V: TryFromObject,
R: IntoPySetResult,
{
fn into_setter(self) -> PySetterFunc {
Box::new(move |vm, obj, value| {
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
let value = V::try_from_object(vm, value)?;
(self)(&zelf, value, vm)
(self)(&zelf, value, vm).into_pysetresult()
})
}
}
Expand Down Expand Up @@ -145,10 +151,11 @@ impl PyGetSet {
}
}

pub fn with_get_set<G, S, GT, GR, ST, SV>(name: String, getter: G, setter: S) -> Self
pub fn with_get_set<G, S, GT, GR, ST, SV, SR>(name: String, getter: G, setter: S) -> Self
where
G: IntoPyGetterFunc<GT, GR>,
S: IntoPySetterFunc<ST, SV>,
S: IntoPySetterFunc<ST, SV, SR>,
SR: IntoPySetResult,
{
Self {
name,
Expand All @@ -163,7 +170,7 @@ impl PyGetSet {
// Descriptor methods

#[pymethod(magic)]
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
fn set(&self, obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PySetResult {
if let Some(ref f) = self.setter {
f(vm, obj, value)
} else {
Expand Down
6 changes: 3 additions & 3 deletions vm/src/obj/objobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::function::{OptionalArg, PyFuncArgs};
use crate::pyhash;
use crate::pyobject::{
IdProtocol, ItemProtocol, PyArithmaticValue::*, PyAttributes, PyClassImpl, PyComparisonValue,
PyContext, PyObject, PyObjectRef, PyResult, PyValue, TryFromObject, TypeProtocol,
PyContext, PyObject, PyObjectRef, PyResult, PySetResult, PyValue, TryFromObject, TypeProtocol,
};
use crate::vm::VirtualMachine;

Expand Down Expand Up @@ -180,7 +180,7 @@ impl PyBaseObject {
}

#[pyproperty(name = "__class__", setter)]
fn set_class(instance: PyObjectRef, _value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
fn set_class(instance: PyObjectRef, _value: PyObjectRef, vm: &VirtualMachine) -> PySetResult {
let type_repr = vm.to_pystr(&instance.class())?;
Err(vm.new_type_error(format!("can't change class of type '{}'", type_repr)))
}
Expand Down Expand Up @@ -237,7 +237,7 @@ pub(crate) fn setattr(
attr_name: PyStringRef,
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
) -> PySetResult {
vm_trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value);
let cls = obj.class();

Expand Down
11 changes: 3 additions & 8 deletions vm/src/obj/objproperty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use std::cell::RefCell;
use super::objtype::PyClassRef;
use crate::function::{IntoPyNativeFunc, OptionalArg};
use crate::pyobject::{
IdProtocol, PyClassImpl, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue,
TypeProtocol,
IdProtocol, IntoPySetResult, PyClassImpl, PyContext, PyObject, PyObjectRef, PyRef, PyResult,
PyValue, TypeProtocol,
};
use crate::slots::PyBuiltinDescriptor;
use crate::vm::VirtualMachine;
Expand Down Expand Up @@ -259,11 +259,6 @@ pub struct PropertyBuilder<'a> {
setter: Option<PyObjectRef>,
}

pub trait PropertySetterResult {}

impl PropertySetterResult for PyResult<()> {}
impl PropertySetterResult for () {}

impl<'a> PropertyBuilder<'a> {
pub fn new(ctx: &'a PyContext) -> Self {
Self {
Expand All @@ -282,7 +277,7 @@ impl<'a> PropertyBuilder<'a> {
}
}

pub fn add_setter<I, V, VM, F: IntoPyNativeFunc<(I, V), impl PropertySetterResult, VM>>(
pub fn add_setter<I, V, VM, F: IntoPyNativeFunc<(I, V), impl IntoPySetResult, VM>>(
self,
func: F,
) -> Self {
Expand Down
19 changes: 19 additions & 0 deletions vm/src/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ pub type PyObjectRef = Rc<PyObject<dyn PyObjectPayload>>;
/// since exceptions are also python objects.
pub type PyResult<T = PyObjectRef> = Result<T, PyBaseExceptionRef>; // A valid value, or an exception

/// Use this type for functions which return None or an exception.
pub type PySetResult = PyResult<()>; // None, or an exception

/// For attributes we do not use a dict, but a hashmap. This is probably
/// faster, unordered, and only supports strings as keys.
/// TODO: class attributes should maintain insertion order (use IndexMap here)
Expand Down Expand Up @@ -1054,6 +1057,22 @@ where
}
}

pub trait IntoPySetResult {
fn into_pysetresult(self) -> PySetResult;
}

impl IntoPySetResult for () {
fn into_pysetresult(self) -> PySetResult {
Ok(())
}
}

impl IntoPySetResult for PySetResult {
fn into_pysetresult(self) -> PySetResult {
self
}
}

impl<T> PyObject<T>
where
T: Sized + PyObjectPayload,
Expand Down