8000 object.__getstate__ · RustPython/RustPython@a9f4de0 · GitHub
[go: up one dir, main page]

Skip to content

Commit a9f4de0

Browse files
committed
object.__getstate__
1 parent f5c1596 commit a9f4de0

File tree

4 files changed

+120
-3
lines changed

4 files changed

+120
-3
lines changed

vm/src/builtins/list.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,9 @@ impl PyList {
174174
Self::new_ref(self.borrow_vec().to_vec(), &vm.ctx)
175175
}
176176

177+
#[allow(clippy::len_without_is_empty)]
177178
#[pymethod(magic)]
178-
fn len(&self) -> usize {
179+
pub fn len(&self) -> usize {
179180
self.borrow_vec().len()
180181
}
181182

vm/src/builtins/object.rs

Lines changed: 115 additions & 0 deletions
F438
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::common::hash::PyHash;
33
use crate::types::PyTypeFlags;
44
use crate::{
55
class::PyClassImpl,
6+
convert::ToPyResult,
67
function::{Either, FuncArgs, PyArithmeticValue, PyComparisonValue, PySetterValue},
78
types::{Constructor, PyComparisonOp},
89
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
@@ -73,8 +74,122 @@ impl Constructor for PyBaseObject {
7374
}
7475
}
7576

77+
// TODO: implement _PyType_GetSlotNames properly
78+
fn type_slot_names(typ: &Py<PyType>, vm: &VirtualMachine) -> PyResult<Option<super::PyListRef>> {
79+
let copyreg = vm.import("copyreg", 0)?;
80+
let copyreg_slotnames = copyreg.get_attr("_slotnames", vm)?;
81+
let slot_names = copyreg_slotnames.call((typ.to_owned(),), vm)?;
82+
let result = match_class!(match slot_names {
83+
l @ super::PyList => Some(l),
84+
_n @ super::PyNone => None,
85+
_ =>
86+
return Err(
87+
vm.new_type_error("copyreg._slotnames didn't return a list or None".to_owned())
88+
),
89+
});
90+
Ok(result)
91+
}
92+
93+
// object_getstate_default in CPython
94+
fn object_getstate_default(obj: &PyObject, required: bool, vm: &VirtualMachine) -> PyResult {
95+
// TODO: itemsize
96+
// if required && obj.class().slots.itemsize > 0 {
97+
// return vm.new_type_error(format!(
98+
// "cannot pickle {:.200} objects",
99+
// obj.class().name()
100+
// ));
101+
// }
102+
103+
let state = if obj.dict().map_or(true, |d| d.is_empty()) {
104+
vm.ctx.none()
105+
} else {
106+
// let state = object_get_dict(obj.clone(), obj.ctx()).unwrap();
107+
let Some(state) = obj.dict() else {
108+
return Ok(vm.ctx.none());
109+
};
110+
state.into()
111+
};
112+
113+
let slot_names = type_slot_names(obj.class(), vm)
114+
.map_err(|_| vm.new_type_error("cannot pickle object".to_owned()))?;
115+
116+
if required {
117+
let mut basicsize = obj.class().slots.basicsize;
118+
// if obj.class().slots.dictoffset > 0
119+
// && !obj.class().slots.flags.has_feature(PyTypeFlags::MANAGED_DICT)
120+
// {
121+
// basicsize += std::mem::size_of::<PyObjectRef>();
122+
// }
123+
// if obj.class().slots.weaklistoffset > 0 {
124+
// basicsize += std::mem::size_of::<PyObjectRef>();
125+
// }
126+
if let Some(ref slot_names) = slot_names {
127+
basicsize += std::mem::size_of::<PyObjectRef>() * slot_names.len();
128+
}
129+
if obj.class().slots.basicsize > basicsize {
130+
return Err(
131+
vm.new_type_error(format!("cannot pickle {:.200} object", obj.class().name()))
132+
);
133+
}
134+
}
135+
136+
if let Some(slot_names) = slot_names {
137+
let slot_names_len = slot_names.len();
138+
if slot_names_len > 0 {
139+
let slots = vm.ctx.new_dict();
140+
for i in 0..slot_names_len {
141+
let borrowed_names = slot_names.borrow_vec();
142+
let name = borrowed_names[i].downcast_ref::<PyStr>().unwrap();
143+
let value = obj.get_attr(name, vm)?;
144+
slots.set_item(name.as_str(), value, vm).unwrap();
145+
}
146+
147+
if slots.len() > 0 {
148+
return (state, slots).to_pyresult(vm);
149+
}
150+
}
151+
}
152+
153+
Ok(state)
154+
}
155+
156+
// object_getstate in CPython
157+
// fn object_getstate(
158+
// obj: &PyObject,
159+
// required: bool,
160+
// vm: &VirtualMachine,
161+
// ) -> PyResult {
162+
// let getstate = obj.get_attr(identifier!(vm, __getstate__), vm)?;
163+
// if vm.is_none(&getstate) {
164+
// return Ok(None);
165+
// }
166+
167+
// let getstate = match getstate.downcast_exact::<PyNativeFunction>(vm) {
168+
// Ok(getstate)
169+
// if getstate
170+
// .get_self()
171+
// .map_or(false, |self_obj| self_obj.is(obj))
172+
// && std::ptr::addr_eq(
173+
// getstate.as_func() as *const _,
174+
// &PyBaseObject::__getstate__ as &dyn crate::function::PyNativeFn as *const _,
175+
// ) =>
176+
// {
177+
// return object_getstate_default(obj, required, vm);
178+
// }
179+
// Ok(getstate) => getstate.into_pyref().into(),
180+
// Err(getstate) => getstate,
181+
// };
182+
// getstate.call((), vm)
183+
// }
184+
76185
#[pyclass(with(Constructor), flags(BASETYPE))]
77186
impl PyBaseObject {
187+
#[pymethod(raw)]
188+
fn __getstate__(vm: &VirtualMachine, args: FuncArgs) -> PyResult {
189+
let (zelf,): (PyObjectRef,) = args.bind(vm)?;
190+
object_getstate_default(&zelf, false, vm)
191+
}
192+
78193
#[pyslot]
79194
fn slot_richcompare(
80195
zelf: &PyObject,

vm/src/protocol/object.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,8 @@ impl PyObject {
564564
}
565565

566566
// int PyObject_TypeCheck(PyObject *o, PyTypeObject *type)
567-
pub fn type_check(&self, typ: PyTypeRef) -> bool {
568-
self.fast_isinstance(&typ)
567+
pub fn type_check(&self, typ: &Py<PyType>) -> bool {
568+
self.fast_isinstance(typ)
569569
}
570570

571571
pub fn length_opt(&self, vm: &VirtualMachine) -> Option<PyResult<usize>> {

vm/src/vm/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ declare_const_name! {
130130
__getformat__,
131131
__getitem__,
132132
__getnewargs__,
133+
__getstate__,
133134
__gt__,
134135
__hash__,
135136
__iadd__,

0 commit comments

Comments
 (0)
0