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