use crate::{AnyThread, ClassType, MainThreadOnly, ThreadKind}; /// Helper for ensuring that `ClassType::ThreadKind`, if specified, is set /// correctly. pub trait ValidThreadKind where Self: ClassType, // Ensure the user did not attempt to declare or define a root class. Self::Super: ClassType, { // Required to reference the trait. fn check() {} } /// Always allow setting `MainThreadOnly`. impl<'a, Cls> ValidThreadKind for Cls where Self: ClassType, Self::Super: ClassType, { } /// But restrict `AnyThread` to only if the superclass also sets it. impl<'a, 'b, Cls> ValidThreadKind for Cls where Self: ClassType, Self::Super: ClassType, { } /// Check that `MainThreadOnly` types do not implement `Send` and `Sync`. /// /// Check implemented using type inference: /// let _ = >::check pub trait MainThreadOnlyDoesNotImplSendSync { // Required to reference the trait. fn check() {} } // Type inference will find this blanket impl... impl MainThreadOnlyDoesNotImplSendSync<()> for Cls {} // ... unless one of these impls also apply, then type inference fails. struct ImplsSend; impl MainThreadOnlyDoesNotImplSendSync for Cls {} struct ImplsSync; impl MainThreadOnlyDoesNotImplSendSync for Cls {} /// Check that class does not implement `Drop`. /// /// This is not needed for soundness, it's just a nice footgun to avoid (since /// it wouldn't ever get called). /// /// Check implemented using type inference: /// let _ = >::check pub trait DoesNotImplDrop { // Required to reference the trait. fn check() {} } // Type inference will find this blanket impl... impl DoesNotImplDrop<()> for Cls {} // ... unless this impl also applies, then type inference fails. struct ImplsDrop; #[allow(drop_bounds)] // We're intentionally using `Drop` as a bound. impl DoesNotImplDrop for Cls {} #[cfg(test)] mod tests { use super::*; use crate::extern_class; use crate::runtime::NSObject; extern_class!( #[unsafe(super(NSObject))] #[thread_kind = AnyThread] #[name = "NSObject"] struct SetAnyThread; ); extern_class!( #[unsafe(super(NSObject))] #[thread_kind = AnyThread] #[name = "NSObject"] struct SendSync; ); unsafe impl Send for SendSync {} unsafe impl Sync for SendSync {} extern_class!( #[unsafe(super(NSObject))] #[thread_kind = MainThreadOnly] #[name = "NSObject"] struct OnlyMain; ); extern_class!( #[unsafe(super(OnlyMain))] #[name = "NSObject"] struct OnlyMainSubDefault; ); extern_class!( #[unsafe(super(OnlyMain))] #[thread_kind = MainThreadOnly] #[name = "NSObject"] struct OnlyMainSubExplicit; ); }