Skip to content

Commit

Permalink
Allow using .into to convert to retained objects
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Sep 18, 2024
1 parent 6b04188 commit 84152d8
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
1 change: 1 addition & 0 deletions crates/objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Implemented `AsRef` in a forwarding fashion on `Retained`.
* Implemented `PartialEq` and `PartialOrd` on `Retained` in a slightly more
generic way.
* Allow using `Into` to convert to retained objects.

### Changed
* **BREAKING**: Changed how you specify a class to only be available on the
Expand Down
45 changes: 45 additions & 0 deletions crates/objc2/src/rc/retained.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,36 @@ impl<T: ?Sized> fmt::Pointer for Retained<T> {
}
}

// Sadly, it is not possible to implement general conversions between
// `Retained`, as it conflicts with the generic `impl From<T> for T`.
//
// impl<T: Upcast, U> From<Retained<U>> for Retained<T> {
// fn from(obj: &Retained<T>) -> Self {
// obj.as_super().retain()
// }
// }
//
// But we _can_ do the following implementations:

impl<T: ?Sized + AsRef<U>, U: Message> From<&T> for Retained<U> {
/// Cast the object to its superclass, and retain it.
#[inline]
fn from(obj: &T) -> Self {
obj.as_ref().retain()
}
}

// Bounded by `T: ClassType` to prevent overlapping impls
// (`AnyObject` implements `Message`).
impl<T: ClassType + 'static> From<Retained<T>> for Retained<AnyObject> {
/// Convert the object to `AnyObject`.
#[inline]
fn from(obj: Retained<T>) -> Self {
// SAFETY: All 'static objects can be converted to `AnyObject`.
unsafe { Retained::cast_unchecked(obj) }
}
}

/// `Retained<T>` is `Send` if `T` is `Send + Sync`.
//
// SAFETY:
Expand Down Expand Up @@ -973,4 +1003,19 @@ mod tests {
assert_eq!(size_of::<Retained<NSObject>>(), ptr_size);
assert_eq!(size_of::<Option<Retained<NSObject>>>(), ptr_size);
}

#[test]
fn test_into() {
let obj = NSObject::new();
let obj: Retained<NSObject> = Into::into(obj);
let _: Retained<AnyObject> = Into::into(obj);

let obj_ref = &*NSObject::new();
let _: Retained<NSObject> = Into::into(obj_ref);
let _: Retained<AnyObject> = Into::into(obj_ref);

let obj_retained_ref = &NSObject::new();
let _: Retained<NSObject> = Into::into(obj_retained_ref);
let _: Retained<AnyObject> = Into::into(obj_retained_ref);
}
}

0 comments on commit 84152d8

Please sign in to comment.