From bbf87ecf47c194d17f2291d27fa76b99289a5eee Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 9 Sep 2021 15:51:38 +0200 Subject: [PATCH] Use GATs in Ownership to specify mutability of references --- objc2/src/lib.rs | 1 + objc2/src/rc/id.rs | 52 ++++++++++++++------------------------- objc2/src/rc/ownership.rs | 33 ++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/objc2/src/lib.rs b/objc2/src/lib.rs index c81c3ef40..effc51fc4 100644 --- a/objc2/src/lib.rs +++ b/objc2/src/lib.rs @@ -70,6 +70,7 @@ The bindings can be used on Linux or *BSD utilizing the #![deny(unsafe_op_in_unsafe_fn)] // Update in Cargo.toml as well. #![doc(html_root_url = "https://docs.rs/objc2/0.2.7")] +#![feature(generic_associated_types)] extern crate alloc; extern crate std; diff --git a/objc2/src/rc/id.rs b/objc2/src/rc/id.rs index 166e9ea8c..ab7ff9114 100644 --- a/objc2/src/rc/id.rs +++ b/objc2/src/rc/id.rs @@ -236,6 +236,24 @@ impl Id { res as *mut T } + /// Autoreleases the [`Id`], returning a reference bound to the pool. + /// + /// The mutability of the reference varies based on if it's an owned or a + /// shared [`Id`]. + /// + /// The object is not immediately released, but will be when the innermost + /// / current autorelease pool (given as a parameter) is drained. + #[doc(alias = "objc_autorelease")] + #[must_use = "If you don't intend to use the object any more, just drop it as usual"] + #[inline] + #[allow(clippy::needless_lifetimes)] + pub fn autorelease<'p>(self, pool: &'p AutoreleasePool) -> ::Reference<'p, T> { + let ptr = self.autorelease_inner(); + // SAFETY: The pointer is valid as a reference, and we've consumed + // the unique access to the `Id` so mutability is safe. + unsafe { ::as_ref_pool(pool, ptr) } + } + // TODO: objc_retainAutoreleasedReturnValue // TODO: objc_autoreleaseReturnValue // TODO: objc_retainAutorelease @@ -254,23 +272,6 @@ impl Id { // } impl Id { - /// Autoreleases the owned [`Id`], returning a mutable reference bound to - /// the pool. - /// - /// The object is not immediately released, but will be when the innermost - /// / current autorelease pool (given as a parameter) is drained. - #[doc(alias = "objc_autorelease")] - #[must_use = "If you don't intend to use the object any more, just drop it as usual"] - #[inline] - #[allow(clippy::needless_lifetimes)] - #[allow(clippy::mut_from_ref)] - pub fn autorelease<'p>(self, pool: &'p AutoreleasePool) -> &'p mut T { - let ptr = self.autorelease_inner(); - // SAFETY: The pointer is valid as a reference, and we've consumed - // the unique access to the `Id` so mutability is safe. - unsafe { pool.ptr_as_mut(ptr) } - } - /// Promote a shared [`Id`] to an owned one, allowing it to be mutated. /// /// # Safety @@ -290,23 +291,6 @@ impl Id { } } -impl Id { - /// Autoreleases the shared [`Id`], returning an aliased reference bound - /// to the pool. - /// - /// The object is not immediately released, but will be when the innermost - /// / current autorelease pool (given as a parameter) is drained. - #[doc(alias = "objc_autorelease")] - #[must_use = "If you don't intend to use the object any more, just drop it as usual"] - #[inline] - #[allow(clippy::needless_lifetimes)] - pub fn autorelease<'p>(self, pool: &'p AutoreleasePool) -> &'p T { - let ptr = self.autorelease_inner(); - // SAFETY: The pointer is valid as a reference - unsafe { pool.ptr_as_ref(ptr) } - } -} - impl From> for Id { /// Downgrade from an owned to a shared [`Id`], allowing it to be cloned. #[inline] diff --git a/objc2/src/rc/ownership.rs b/objc2/src/rc/ownership.rs index 1cb0b8dd4..39596f920 100644 --- a/objc2/src/rc/ownership.rs +++ b/objc2/src/rc/ownership.rs @@ -1,3 +1,5 @@ +use super::AutoreleasePool; + /// A type used to mark that a struct owns the object(s) it contains, /// so it has the sole references to them. pub enum Owned {} @@ -18,7 +20,32 @@ mod private { /// /// This trait is sealed and not meant to be implemented outside of the this /// crate. -pub trait Ownership: private::Sealed + 'static {} +pub trait Ownership: private::Sealed + 'static { + type Reference<'a, T: 'a>; + + unsafe fn as_ref_pool<'p, T: 'p>( + pool: &'p AutoreleasePool, + ptr: *mut T, + ) -> Self::Reference<'p, T>; +} + +impl Ownership for Owned { + type Reference<'a, T: 'a> = &'a mut T; -impl Ownership for Owned {} -impl Ownership for Shared {} + unsafe fn as_ref_pool<'p, T: 'p>( + pool: &'p AutoreleasePool, + ptr: *mut T, + ) -> Self::Reference<'p, T> { + unsafe { pool.ptr_as_mut(ptr) } + } +} +impl Ownership for Shared { + type Reference<'a, T: 'a> = &'a T; + + unsafe fn as_ref_pool<'p, T: 'p>( + pool: &'p AutoreleasePool, + ptr: *mut T, + ) -> Self::Reference<'p, T> { + unsafe { pool.ptr_as_ref(ptr) } + } +}