Skip to content

Commit

Permalink
Use GATs in Ownership to specify mutability of references
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Sep 9, 2021
1 parent 923b893 commit 9205e82
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 34 deletions.
1 change: 1 addition & 0 deletions objc2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ The bindings can be used on Linux or *BSD utilizing the
#![allow(clippy::missing_safety_doc)]
// 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;
Expand Down
48 changes: 17 additions & 31 deletions objc2/src/rc/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,23 @@ impl<T: Message, O: Ownership> Id<T, O> {
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]
pub fn autorelease<'p>(self, pool: &'p AutoreleasePool) -> <O as Ownership>::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 { <O as Ownership>::as_ref_pool(pool, ptr) }
}

// TODO: objc_retainAutoreleasedReturnValue
// TODO: objc_autoreleaseReturnValue
// TODO: objc_retainAutorelease
Expand All @@ -254,21 +271,6 @@ impl<T: Message, O: Ownership> Id<T, O> {
// }

impl<T: Message> Id<T, Owned> {
/// 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]
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
Expand All @@ -286,22 +288,6 @@ impl<T: Message> Id<T, Owned> {
}
}

impl<T: Message> Id<T, Shared> {
/// 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]
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<T: Message> From<Id<T, Owned>> for Id<T, Shared> {
/// Downgrade from an owned to a shared [`Id`], allowing it to be cloned.
#[inline]
Expand Down
33 changes: 30 additions & 3 deletions objc2/src/rc/ownership.rs
Original file line number Diff line number Diff line change
@@ -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 {}
Expand All @@ -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> {
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> {
pool.ptr_as_ref(ptr)
}
}

0 comments on commit 9205e82

Please sign in to comment.