diff --git a/src/subclass/object.rs b/src/subclass/object.rs index 909dc30e..e30f6eaa 100644 --- a/src/subclass/object.rs +++ b/src/subclass/object.rs @@ -564,6 +564,17 @@ mod test { assert!(weak.upgrade().is_none()); } + #[test] + fn test_create_child_object() { + let type_ = ChildObject::get_type(); + let obj = Object::new(type_, &[]).unwrap(); + + // ChildObject is a zero-sized type and we map that to the same pointer as the object + // itself. No private/impl data is allocated for zero-sized types. + let imp = ChildObject::from_instance(&obj); + assert_eq!(imp as *const _ as *const (), obj.as_ptr() as *const _); + } + #[test] fn test_set_properties() { let obj = Object::new(SimpleObject::get_type(), &[]).unwrap(); diff --git a/src/subclass/types.rs b/src/subclass/types.rs index adfb096b..2f239d64 100644 --- a/src/subclass/types.rs +++ b/src/subclass/types.rs @@ -72,9 +72,9 @@ pub unsafe trait InstanceStruct: Sized + 'static { let private_offset = data.as_ref().private_offset; let ptr: *const u8 = self as *const _ as *const u8; let priv_ptr = ptr.offset(private_offset); - let imp = priv_ptr as *const Option; + let imp = priv_ptr as *const Self::Type; - (*imp).as_ref().expect("No private struct") + &*imp } } @@ -377,7 +377,7 @@ unsafe extern "C" fn class_init( // We have to update the private struct offset once the class is actually // being initialized. - { + if mem::size_of::() != 0 { let mut private_offset = data.as_ref().private_offset as i32; gobject_sys::g_type_class_adjust_private_offset(klass, &mut private_offset); (*data.as_mut()).private_offset = private_offset as isize; @@ -417,26 +417,23 @@ unsafe extern "C" fn instance_init( let private_offset = (*data.as_mut()).private_offset; let ptr: *mut u8 = obj as *mut _ as *mut u8; let priv_ptr = ptr.offset(private_offset); - let imp_storage = priv_ptr as *mut Option; + let imp_storage = priv_ptr as *mut T; let klass = &*(klass as *const T::Class); let imp = T::new_with_class(klass); - ptr::write(imp_storage, Some(imp)); + ptr::write(imp_storage, imp); } unsafe extern "C" fn finalize(obj: *mut gobject_sys::GObject) { - // Retrieve the private struct, take it out of its storage and - // drop it for freeing all associated memory. + // Retrieve the private struct and drop it for freeing all associated memory. let mut data = T::type_data(); let private_offset = (*data.as_mut()).private_offset; let ptr: *mut u8 = obj as *mut _ as *mut u8; let priv_ptr = ptr.offset(private_offset); - let imp_storage = priv_ptr as *mut Option; - - let imp = (*imp_storage).take().expect("No private struct"); - drop(imp); + let imp_storage = priv_ptr as *mut T; + ptr::drop_in_place(imp_storage); // Chain up to the parent class' finalize implementation, if any. let parent_class = &*(data.as_ref().get_parent_class() as *const gobject_sys::GObjectClass); @@ -457,6 +454,16 @@ pub fn register_type() -> Type where <::ParentType as ObjectType>::RustClassType: IsSubclassable, { + // GLib aligns the type private data to two gsizes so we can't safely store any type there that + // requires a bigger alignment. + if mem::align_of::() > 2 * mem::size_of::() { + panic!( + "Alignment {} of type not supported, bigger than {}", + mem::align_of::(), + 2 * mem::size_of::(), + ); + } + unsafe { use std::ffi::CString; @@ -494,8 +501,12 @@ where let mut data = T::type_data(); (*data.as_mut()).type_ = type_; - let private_offset = - gobject_sys::g_type_add_instance_private(type_.to_glib(), mem::size_of::>()); + + let private_offset = if mem::size_of::() == 0 { + 0 + } else { + gobject_sys::g_type_add_instance_private(type_.to_glib(), mem::size_of::()) + }; (*data.as_mut()).private_offset = private_offset as isize; T::type_init(&mut InitializingType::(type_, marker::PhantomData));