Skip to content

Commit caa47b1

Browse files
authored
Merge pull request #586 from sdroege/auto-subclass-send-sync-impls
glib: Automatically implement `Send + Sync` on object subclasses if t…
2 parents f12816e + d37dc8e commit caa47b1

File tree

10 files changed

+265
-33
lines changed

10 files changed

+265
-33
lines changed

.github/workflows/CI.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ jobs:
8585
run: cargo test
8686
working-directory: ${{ matrix.conf.name }}/sys
8787
if: matrix.conf.test_sys
88+
# GLib compile tests only on stable
89+
- name: Compile tests
90+
run: cargo test --manifest-path glib/Cargo.toml --features "compiletests,v2_66"
91+
if: matrix.rust == 'stable'
8892

8993
build-others:
9094
runs-on: ubuntu-latest

glib/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ thiserror = "1"
3737
[dev-dependencies]
3838
tempfile = "3"
3939
gir-format-check = "^0.1"
40+
trybuild2 = "1"
4041

4142
[features]
4243
v2_50 = ["ffi/v2_50"]
@@ -54,6 +55,11 @@ v2_72 = ["v2_70", "ffi/v2_72"]
5455
log = ["rs-log"]
5556
log_macros = ["log"]
5657
dox = ["ffi/dox", "gobject_ffi/dox", "log_macros"]
58+
compiletests = []
5759

5860
[package.metadata.docs.rs]
5961
features = ["dox"]
62+
63+
[[test]]
64+
name = "subclass_compiletest"
65+
required-features = ["compiletests"]

glib/src/object.rs

Lines changed: 112 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -597,15 +597,97 @@ impl FromGlibPtrArrayContainerAsVec<*mut GObject, *const *mut GObject> for Objec
597597
}
598598
}
599599

600+
#[repr(transparent)]
601+
pub struct TypedObjectRef<T> {
602+
inner: ObjectRef,
603+
phantom: PhantomData<T>,
604+
}
605+
606+
impl<T> TypedObjectRef<T> {
607+
pub unsafe fn new(obj: ObjectRef) -> Self {
608+
Self {
609+
inner: obj,
610+
phantom: PhantomData,
611+
}
612+
}
613+
614+
pub fn into_inner(self) -> ObjectRef {
615+
self.inner
616+
}
617+
}
618+
619+
impl<T> Clone for TypedObjectRef<T> {
620+
fn clone(&self) -> Self {
621+
Self {
622+
inner: self.inner.clone(),
623+
phantom: PhantomData,
624+
}
625+
}
626+
}
627+
628+
impl<T> ops::Deref for TypedObjectRef<T> {
629+
type Target = ObjectRef;
630+
631+
fn deref(&self) -> &Self::Target {
632+
&self.inner
633+
}
634+
}
635+
636+
impl<T> fmt::Debug for TypedObjectRef<T> {
637+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
638+
let type_ = unsafe {
639+
let klass = (*self.inner.inner.as_ptr()).g_type_instance.g_class as *const ObjectClass;
640+
(*klass).type_()
641+
};
642+
643+
f.debug_struct("TypedObjectRef")
644+
.field("inner", &self.inner.inner)
645+
.field("type", &type_)
646+
.finish()
647+
}
648+
}
649+
650+
impl<T> PartialOrd for TypedObjectRef<T> {
651+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
652+
self.inner.partial_cmp(&other.inner)
653+
}
654+
}
655+
656+
impl<T> Ord for TypedObjectRef<T> {
657+
fn cmp(&self, other: &Self) -> cmp::Ordering {
658+
self.inner.cmp(&other.inner)
659+
}
660+
}
661+
662+
impl<T> PartialEq for TypedObjectRef<T> {
663+
fn eq(&self, other: &Self) -> bool {
664+
self.inner == other.inner
665+
}
666+
}
667+
668+
impl<T> Eq for TypedObjectRef<T> {}
669+
670+
impl<T> hash::Hash for TypedObjectRef<T> {
671+
fn hash<H>(&self, state: &mut H)
672+
where
673+
H: hash::Hasher,
674+
{
675+
self.inner.hash(state)
676+
}
677+
}
678+
679+
unsafe impl<T: Send + Sync> Send for TypedObjectRef<T> {}
680+
unsafe impl<T: Send + Sync> Sync for TypedObjectRef<T> {}
681+
600682
// rustdoc-stripper-ignore-next
601683
/// ObjectType implementations for Object types. See `wrapper!`.
602684
#[macro_export]
603685
macro_rules! glib_object_wrapper {
604-
(@generic_impl [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr) => {
686+
(@generic_impl [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type: ty, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr) => {
605687
$(#[$attr])*
606688
#[repr(transparent)]
607689
$visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? {
608-
inner: $crate::object::ObjectRef,
690+
inner: $crate::object::TypedObjectRef<$inner_type>,
609691
phantom: std::marker::PhantomData<($($($generic),+)?)>,
610692
}
611693

@@ -639,7 +721,7 @@ macro_rules! glib_object_wrapper {
639721
impl<OT: $crate::object::ObjectType $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> std::cmp::PartialEq<OT> for $name $(<$($generic),+>)? {
640722
#[inline]
641723
fn eq(&self, other: &OT) -> bool {
642-
std::cmp::PartialEq::eq(&self.inner, $crate::object::ObjectType::as_object_ref(other))
724+
std::cmp::PartialEq::eq(&*self.inner, $crate::object::ObjectType::as_object_ref(other))
643725
}
644726
}
645727

@@ -648,14 +730,14 @@ macro_rules! glib_object_wrapper {
648730
impl<OT: $crate::object::ObjectType $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> std::cmp::PartialOrd<OT> for $name $(<$($generic),+>)? {
649731
#[inline]
650732
fn partial_cmp(&self, other: &OT) -> Option<std::cmp::Ordering> {
651-
std::cmp::PartialOrd::partial_cmp(&self.inner, $crate::object::ObjectType::as_object_ref(other))
733+
std::cmp::PartialOrd::partial_cmp(&*self.inner, $crate::object::ObjectType::as_object_ref(other))
652734
}
653735
}
654736

655737
impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::cmp::Ord for $name $(<$($generic),+>)? {
656738
#[inline]
657739
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
658-
std::cmp::Ord::cmp(&self.inner, $crate::object::ObjectType::as_object_ref(other))
740+
std::cmp::Ord::cmp(&*self.inner, $crate::object::ObjectType::as_object_ref(other))
659741
}
660742
}
661743

@@ -668,15 +750,15 @@ macro_rules! glib_object_wrapper {
668750
#[doc(hidden)]
669751
impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? From<$name $(<$($generic),+>)?> for $crate::object::ObjectRef {
670752
fn from(s: $name $(<$($generic),+>)?) -> $crate::object::ObjectRef {
671-
s.inner
753+
s.inner.into_inner()
672754
}
673755
}
674756

675757
#[doc(hidden)]
676758
impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::UnsafeFrom<$crate::object::ObjectRef> for $name $(<$($generic),+>)? {
677759
unsafe fn unsafe_from(t: $crate::object::ObjectRef) -> Self {
678760
$name {
679-
inner: t,
761+
inner: $crate::object::TypedObjectRef::new(t),
680762
phantom: std::marker::PhantomData,
681763
}
682764
}
@@ -697,7 +779,7 @@ macro_rules! glib_object_wrapper {
697779
}
698780

699781
fn as_ptr(&self) -> *mut Self::GlibType {
700-
$crate::translate::ToGlibPtr::to_glib_none(&self.inner).0 as *mut _
782+
$crate::translate::ToGlibPtr::to_glib_none(&*self.inner).0 as *mut _
701783
}
702784
}
703785

@@ -733,13 +815,13 @@ macro_rules! glib_object_wrapper {
733815

734816
#[inline]
735817
fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> {
736-
let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.inner);
818+
let stash = $crate::translate::ToGlibPtr::to_glib_none(&*self.inner);
737819
$crate::translate::Stash(stash.0 as *const _, stash.1)
738820
}
739821

740822
#[inline]
741823
fn to_glib_full(&self) -> *const $ffi_name {
742-
$crate::translate::ToGlibPtr::to_glib_full(&self.inner) as *const _
824+
$crate::translate::ToGlibPtr::to_glib_full(&*self.inner) as *const _
743825
}
744826
}
745827

@@ -750,13 +832,13 @@ macro_rules! glib_object_wrapper {
750832

751833
#[inline]
752834
fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $ffi_name, Self> {
753-
let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.inner);
835+
let stash = $crate::translate::ToGlibPtr::to_glib_none(&*self.inner);
754836
$crate::translate::Stash(stash.0 as *mut _, stash.1)
755837
}
756838

757839
#[inline]
758840
fn to_glib_full(&self) -> *mut $ffi_name {
759-
$crate::translate::ToGlibPtr::to_glib_full(&self.inner) as *mut _
841+
$crate::translate::ToGlibPtr::to_glib_full(&*self.inner) as *mut _
760842
}
761843
}
762844

@@ -828,7 +910,7 @@ macro_rules! glib_object_wrapper {
828910
unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self {
829911
debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
830912
$name {
831-
inner: $crate::translate::from_glib_none(ptr as *mut _),
913+
inner: $crate::object::TypedObjectRef::new($crate::translate::from_glib_none(ptr as *mut _)),
832914
phantom: std::marker::PhantomData,
833915
}
834916
}
@@ -841,7 +923,7 @@ macro_rules! glib_object_wrapper {
841923
unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self {
842924
debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
843925
$name {
844-
inner: $crate::translate::from_glib_none(ptr as *mut _),
926+
inner: $crate::object::TypedObjectRef::new($crate::translate::from_glib_none(ptr as *mut _)),
845927
phantom: std::marker::PhantomData,
846928
}
847929
}
@@ -854,7 +936,7 @@ macro_rules! glib_object_wrapper {
854936
unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self {
855937
debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
856938
$name {
857-
inner: $crate::translate::from_glib_full(ptr as *mut _),
939+
inner: $crate::object::TypedObjectRef::new($crate::translate::from_glib_full(ptr as *mut _)),
858940
phantom: std::marker::PhantomData,
859941
}
860942
}
@@ -868,7 +950,7 @@ macro_rules! glib_object_wrapper {
868950
debug_assert!($crate::types::instance_of::<Self>(ptr as *const _));
869951
$crate::translate::Borrowed::new(
870952
$name {
871-
inner: $crate::translate::from_glib_borrow::<_, $crate::object::ObjectRef>(ptr as *mut _).into_inner(),
953+
inner: $crate::object::TypedObjectRef::new($crate::translate::from_glib_borrow::<_, $crate::object::ObjectRef>(ptr as *mut _).into_inner()),
872954
phantom: std::marker::PhantomData,
873955
}
874956
)
@@ -1100,27 +1182,27 @@ macro_rules! glib_object_wrapper {
11001182

11011183
// This case is only for glib::Object itself below. All other cases have glib::Object in its
11021184
// parent class list
1103-
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @ffi_class $ffi_class_name:ty, @type_ $get_type_expr:expr) => {
1185+
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty, @type_ $get_type_expr:expr) => {
11041186
$crate::glib_object_wrapper!(
1105-
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, $ffi_class_name,
1187+
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, $ffi_class_name,
11061188
@type_ $get_type_expr);
11071189

11081190
#[doc(hidden)]
11091191
unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::IsClass for $name $(<$($generic),+>)? { }
11101192
};
11111193

1112-
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty,
1194+
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty,
11131195
@type_ $get_type_expr:expr, @extends [$($extends:tt)*], @implements [$($implements:tt)*]) => {
11141196
$crate::glib_object_wrapper!(
1115-
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @ffi_class std::os::raw::c_void,
1197+
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, @ffi_class std::os::raw::c_void,
11161198
@type_ $get_type_expr, @extends [$($extends)*], @implements [$($implements)*]
11171199
);
11181200
};
11191201

1120-
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @ffi_class $ffi_class_name:ty,
1202+
(@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty,
11211203
@type_ $get_type_expr:expr, @extends [$($extends:tt)*], @implements [$($implements:tt)*]) => {
11221204
$crate::glib_object_wrapper!(
1123-
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, $ffi_class_name,
1205+
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, $ffi_class_name,
11241206
@type_ $get_type_expr
11251207
);
11261208

@@ -1146,6 +1228,7 @@ macro_rules! glib_object_wrapper {
11461228
@extends [$($extends:tt)*], @implements [$($implements:tt)*]) => {
11471229
$crate::glib_object_wrapper!(
11481230
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?,
1231+
$subclass,
11491232
<$subclass as $crate::subclass::types::ObjectSubclass>::Instance,
11501233
@ffi_class <$subclass as $crate::subclass::types::ObjectSubclass>::Class,
11511234
@type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()),
@@ -1157,18 +1240,18 @@ macro_rules! glib_object_wrapper {
11571240
}
11581241
};
11591242

1160-
(@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty,
1243+
(@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty,
11611244
@type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => {
11621245
$crate::glib_object_wrapper!(
1163-
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @ffi_class std::os::raw::c_void,
1246+
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, @ffi_class std::os::raw::c_void,
11641247
@type_ $get_type_expr, @requires [$($requires)*]
11651248
);
11661249
};
11671250

1168-
(@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @ffi_class $ffi_class_name:ty,
1251+
(@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $inner_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty,
11691252
@type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => {
11701253
$crate::glib_object_wrapper!(
1171-
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, $ffi_class_name,
1254+
@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $inner_type, $ffi_name, $ffi_class_name,
11721255
@type_ $get_type_expr
11731256
);
11741257
$crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $($requires)*);
@@ -1190,7 +1273,7 @@ macro_rules! glib_object_wrapper {
11901273

11911274
glib_object_wrapper!(@object
11921275
[doc = "The base class in the object hierarchy."]
1193-
pub Object, GObject, @ffi_class GObjectClass, @type_ gobject_ffi::g_object_get_type()
1276+
pub Object, *mut std::os::raw::c_void, GObject, @ffi_class GObjectClass, @type_ gobject_ffi::g_object_get_type()
11941277
);
11951278
pub type ObjectClass = Class<Object>;
11961279

@@ -3720,11 +3803,11 @@ impl<'a> BindingBuilder<'a> {
37203803

37213804
unsafe {
37223805
let source = Object {
3723-
inner: self.source.clone(),
3806+
inner: TypedObjectRef::new(self.source.clone()),
37243807
phantom: std::marker::PhantomData,
37253808
};
37263809
let target = Object {
3727-
inner: self.target.clone(),
3810+
inner: TypedObjectRef::new(self.target.clone()),
37283811
phantom: std::marker::PhantomData,
37293812
};
37303813

glib/src/wrapper.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ macro_rules! wrapper {
363363
}
364364
) => {
365365
$crate::glib_object_wrapper!(
366-
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name,
366+
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name,
367367
$( @ffi_class $ffi_class_name ,)?
368368
@type_ $get_type_expr,
369369
@extends [],
@@ -381,7 +381,7 @@ macro_rules! wrapper {
381381
}
382382
) => {
383383
$crate::glib_object_wrapper!(
384-
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name,
384+
@object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name,
385385
$( @ffi_class $ffi_class_name ,)?
386386
@type_ $get_type_expr,
387387
@extends [$($extends),+],
@@ -423,7 +423,7 @@ macro_rules! wrapper {
423423
}
424424
) => {
425425
$crate::glib_object_wrapper!(
426-
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name,
426+
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name,
427427
$( @ffi_class $ffi_class_name ,)?
428428
@type_ $get_type_expr,
429429
@requires [$( $($requires),+ )?]
@@ -436,7 +436,7 @@ macro_rules! wrapper {
436436
$visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectInterface<$iface_name:ty>) $(@requires $($requires:path),+)?;
437437
) => {
438438
$crate::glib_object_wrapper!(
439-
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, std::os::raw::c_void,
439+
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, std::os::raw::c_void,
440440
@ffi_class $iface_name,
441441
@type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()),
442442
@requires [$( $($requires),+ )?]

glib/tests/subclass_compiletest.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#[test]
2+
pub fn test() {
3+
let t = trybuild2::TestCases::new();
4+
5+
t.pass("tests/subclass_compiletest/01-auto-send-sync.rs");
6+
t.compile_fail("tests/subclass_compiletest/02-no-auto-send-sync.rs");
7+
t.compile_fail("tests/subclass_compiletest/03-object-no-auto-send-sync.rs");
8+
}

0 commit comments

Comments
 (0)