object_getstate_default
(obj: &PyObject, required: bool, vm: &VirtualMachine)
| 190 | |
| 191 | // object_getstate_default |
| 192 | fn object_getstate_default(obj: &PyObject, required: bool, vm: &VirtualMachine) -> PyResult { |
| 193 | // Check itemsize |
| 194 | if required && obj.class().slots.itemsize > 0 { |
| 195 | return Err(vm.new_type_error(format!("cannot pickle {:.200} objects", obj.class().name()))); |
| 196 | } |
| 197 | |
| 198 | let state = if obj.dict().is_none_or(|d| d.is_empty()) { |
| 199 | vm.ctx.none() |
| 200 | } else { |
| 201 | // let state = object_get_dict(obj.clone(), obj.ctx()).unwrap(); |
| 202 | let Some(state) = obj.dict() else { |
| 203 | return Ok(vm.ctx.none()); |
| 204 | }; |
| 205 | state.into() |
| 206 | }; |
| 207 | |
| 208 | let slot_names = |
| 209 | type_slot_names(obj.class(), vm).map_err(|_| vm.new_type_error("cannot pickle object"))?; |
| 210 | |
| 211 | if required { |
| 212 | // Start with PyBaseObject_Type's basicsize |
| 213 | let mut basicsize = vm.ctx.types.object_type.slots.basicsize; |
| 214 | |
| 215 | // Add __dict__ size if type has dict |
| 216 | if obj.class().slots.flags.has_feature(PyTypeFlags::HAS_DICT) { |
| 217 | basicsize += core::mem::size_of::<PyObjectRef>(); |
| 218 | } |
| 219 | |
| 220 | // Add __weakref__ size if type has weakref support |
| 221 | let has_weakref = if let Some(ref ext) = obj.class().heaptype_ext { |
| 222 | match &ext.slots { |
| 223 | None => true, // Heap type without __slots__ has automatic weakref |
| 224 | Some(slots) => slots.iter().any(|s| s.as_bytes() == b"__weakref__"), |
| 225 | } |
| 226 | } else { |
| 227 | let weakref_name = vm.ctx.intern_str("__weakref__"); |
| 228 | obj.class().attributes.read().contains_key(weakref_name) |
| 229 | }; |
| 230 | if has_weakref { |
| 231 | basicsize += core::mem::size_of::<PyObjectRef>(); |
| 232 | } |
| 233 | |
| 234 | // Add slots size |
| 235 | if let Some(ref slot_names) = slot_names { |
| 236 | basicsize += core::mem::size_of::<PyObjectRef>() * slot_names.__len__(); |
| 237 | } |
| 238 | |
| 239 | // Fail if actual type's basicsize > expected basicsize |
| 240 | if obj.class().slots.basicsize > basicsize { |
| 241 | return Err(vm.new_type_error(format!("cannot pickle '{}' object", obj.class().name()))); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | if let Some(slot_names) = slot_names { |
| 246 | let slot_names_len = slot_names.__len__(); |
| 247 | if slot_names_len > 0 { |
| 248 | let slots = vm.ctx.new_dict(); |
| 249 | for i in 0..slot_names_len { |
no test coverage detected