@@ -3,6 +3,7 @@ use crate::common::hash::PyHash;
3
3
use crate :: types:: PyTypeFlags ;
4
4
use crate :: {
5
5
class:: PyClassImpl ,
6
+ convert:: ToPyResult ,
6
7
function:: { Either , FuncArgs , PyArithmeticValue , PyComparisonValue , PySetterValue } ,
7
8
types:: { Constructor , PyComparisonOp } ,
8
9
AsObject , Context , Py , PyObject , PyObjectRef , PyPayload , PyResult , VirtualMachine ,
@@ -73,8 +74,122 @@ impl Constructor for PyBaseObject {
73
74
}
74
75
}
75
76
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
+ // {
F438
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
+
76
185
#[ pyclass( with( Constructor ) , flags( BASETYPE ) ) ]
77
186
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
+
78
193
#[ pyslot]
79
194
fn slot_richcompare (
80
195
zelf : & PyObject ,
0 commit comments