Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Commit 28a774a

Browse files
authored
Merge pull request #589 from sdroege/subclass-no-option-impl
Don't store subclass impl/private data in an Option<T>
2 parents 691941a + 155ea11 commit 28a774a

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

src/subclass/object.rs

+11
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,17 @@ mod test {
564564
assert!(weak.upgrade().is_none());
565565
}
566566

567+
#[test]
568+
fn test_create_child_object() {
569+
let type_ = ChildObject::get_type();
570+
let obj = Object::new(type_, &[]).unwrap();
571+
572+
// ChildObject is a zero-sized type and we map that to the same pointer as the object
573+
// itself. No private/impl data is allocated for zero-sized types.
574+
let imp = ChildObject::from_instance(&obj);
575+
assert_eq!(imp as *const _ as *const (), obj.as_ptr() as *const _);
576+
}
577+
567578
#[test]
568579
fn test_set_properties() {
569580
let obj = Object::new(SimpleObject::get_type(), &[]).unwrap();

src/subclass/types.rs

+24-13
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ pub unsafe trait InstanceStruct: Sized + 'static {
7272
let private_offset = data.as_ref().private_offset;
7373
let ptr: *const u8 = self as *const _ as *const u8;
7474
let priv_ptr = ptr.offset(private_offset);
75-
let imp = priv_ptr as *const Option<Self::Type>;
75+
let imp = priv_ptr as *const Self::Type;
7676

77-
(*imp).as_ref().expect("No private struct")
77+
&*imp
7878
}
7979
}
8080

@@ -377,7 +377,7 @@ unsafe extern "C" fn class_init<T: ObjectSubclass>(
377377

378378
// We have to update the private struct offset once the class is actually
379379
// being initialized.
380-
{
380+
if mem::size_of::<T>() != 0 {
381381
let mut private_offset = data.as_ref().private_offset as i32;
382382
gobject_sys::g_type_class_adjust_private_offset(klass, &mut private_offset);
383383
(*data.as_mut()).private_offset = private_offset as isize;
@@ -417,26 +417,23 @@ unsafe extern "C" fn instance_init<T: ObjectSubclass>(
417417
let private_offset = (*data.as_mut()).private_offset;
418418
let ptr: *mut u8 = obj as *mut _ as *mut u8;
419419
let priv_ptr = ptr.offset(private_offset);
420-
let imp_storage = priv_ptr as *mut Option<T>;
420+
let imp_storage = priv_ptr as *mut T;
421421

422422
let klass = &*(klass as *const T::Class);
423423

424424
let imp = T::new_with_class(klass);
425425

426-
ptr::write(imp_storage, Some(imp));
426+
ptr::write(imp_storage, imp);
427427
}
428428

429429
unsafe extern "C" fn finalize<T: ObjectSubclass>(obj: *mut gobject_sys::GObject) {
430-
// Retrieve the private struct, take it out of its storage and
431-
// drop it for freeing all associated memory.
430+
// Retrieve the private struct and drop it for freeing all associated memory.
432431
let mut data = T::type_data();
433432
let private_offset = (*data.as_mut()).private_offset;
434433
let ptr: *mut u8 = obj as *mut _ as *mut u8;
435434
let priv_ptr = ptr.offset(private_offset);
436-
let imp_storage = priv_ptr as *mut Option<T>;
437-
438-
let imp = (*imp_storage).take().expect("No private struct");
439-
drop(imp);
435+
let imp_storage = priv_ptr as *mut T;
436+
ptr::drop_in_place(imp_storage);
440437

441438
// Chain up to the parent class' finalize implementation, if any.
442439
let parent_class = &*(data.as_ref().get_parent_class() as *const gobject_sys::GObjectClass);
@@ -457,6 +454,16 @@ pub fn register_type<T: ObjectSubclass>() -> Type
457454
where
458455
<<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType: IsSubclassable<T>,
459456
{
457+
// GLib aligns the type private data to two gsizes so we can't safely store any type there that
458+
// requires a bigger alignment.
459+
if mem::align_of::<T>() > 2 * mem::size_of::<usize>() {
460+
panic!(
461+
"Alignment {} of type not supported, bigger than {}",
462+
mem::align_of::<T>(),
463+
2 * mem::size_of::<usize>(),
464+
);
465+
}
466+
460467
unsafe {
461468
use std::ffi::CString;
462469

@@ -494,8 +501,12 @@ where
494501

495502
let mut data = T::type_data();
496503
(*data.as_mut()).type_ = type_;
497-
let private_offset =
498-
gobject_sys::g_type_add_instance_private(type_.to_glib(), mem::size_of::<Option<T>>());
504+
505+
let private_offset = if mem::size_of::<T>() == 0 {
506+
0
507+
} else {
508+
gobject_sys::g_type_add_instance_private(type_.to_glib(), mem::size_of::<T>())
509+
};
499510
(*data.as_mut()).private_offset = private_offset as isize;
500511

501512
T::type_init(&mut InitializingType::<T>(type_, marker::PhantomData));

0 commit comments

Comments
 (0)