Skip to content

Commit

Permalink
Add unstable_extern_types feature
Browse files Browse the repository at this point in the history
To see what changes we'd have to make in the library to use `extern type` (RFC-1861) (when it's is stabilized).

Unfortunately had to change some usage of `ptr::null[_mut]` to `0 as *const/mut X`, see rust-lang/rust#42847.
  • Loading branch information
madsmtm committed Dec 22, 2021
1 parent 048b72f commit 7c496ce
Show file tree
Hide file tree
Showing 12 changed files with 38 additions and 20 deletions.
3 changes: 3 additions & 0 deletions objc-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ winobjc = ["gnustep-1-8"]
# TODO
objfw = []

# Marks opaque types as !Sized
unstable_extern_types = []

[package.metadata.docs.rs]
default-target = "x86_64-apple-darwin"

Expand Down
13 changes: 11 additions & 2 deletions objc-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! [objc4-mirror]: https://github.com/madsmtm/objc4-mirror.git

#![no_std]
#![cfg_attr(feature = "unstable_extern_types", feature(extern_types))]
#![allow(clippy::upper_case_acronyms)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
Expand All @@ -26,8 +27,11 @@
// See https://github.com/japaric/cty/issues/14.
extern crate std;

use core::cell::UnsafeCell;
use core::marker::{PhantomData, PhantomPinned};
#[cfg(not(feature = "unstable_extern_types"))]
use core::{
cell::UnsafeCell,
marker::{PhantomData, PhantomPinned},
};

mod class;
mod constants;
Expand Down Expand Up @@ -63,4 +67,9 @@ pub use various::*;
/// (It's also less of a breaking change on our part if we re-add these).
///
/// TODO: Replace this with `extern type` to also mark it as `!Sized`.
#[cfg(not(feature = "unstable_extern_types"))]
type OpaqueData = PhantomData<(UnsafeCell<()>, *const UnsafeCell<()>, PhantomPinned)>;
#[cfg(feature = "unstable_extern_types")]
extern "C" {
type OpaqueData;
}
2 changes: 2 additions & 0 deletions objc2-foundation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ default = ["block"]
# Provided as a way to cut down on dependencies
block = ["block2"]

unstable_extern_types = ["objc2/unstable_extern_types", "objc-sys/unstable_extern_types"]

[dependencies]
# Exact dependencies, because block2 and objc2 are expected to change
block2 = { path = "../block2", version = "=0.2.0-alpha.1", optional = true }
Expand Down
1 change: 1 addition & 0 deletions objc2-foundation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![no_std]
#![cfg_attr(feature = "unstable_extern_types", feature(extern_types))]
#![warn(elided_lifetimes_in_paths)]
#![deny(non_ascii_idents)]
#![warn(unreachable_pub)]
Expand Down
1 change: 1 addition & 0 deletions objc2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ malloc = ["malloc_buf"]

# Uses nightly features to make AutoreleasePool zero-cost even in debug mode
unstable_autoreleasesafe = []
unstable_extern_types = ["objc-sys/unstable_extern_types"]

[dependencies]
malloc_buf = { version = "1.0", optional = true }
Expand Down
4 changes: 2 additions & 2 deletions objc2/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl CachedSel {
/// Allows storing a [`Class`] reference in a static and lazily loading it.
#[doc(hidden)]
pub struct CachedClass {
ptr: AtomicPtr<Class>,
ptr: AtomicPtr<c_void>,
}

impl CachedClass {
Expand All @@ -56,7 +56,7 @@ impl CachedClass {
#[doc(hidden)]
pub unsafe fn get(&self, name: &str) -> Option<&'static Class> {
// `Relaxed` should be fine since `objc_getClass` is thread-safe.
let ptr = self.ptr.load(Ordering::Relaxed);
let ptr = self.ptr.load(Ordering::Relaxed) as *const Class;
if ptr.is_null() {
let cls = unsafe { ffi::objc_getClass(name.as_ptr() as *const _) } as *const Class;
self.ptr.store(cls as *mut _, Ordering::Relaxed);
Expand Down
3 changes: 1 addition & 2 deletions objc2/src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ use alloc::format;
use alloc::string::ToString;
use core::mem;
use core::mem::ManuallyDrop;
use core::ptr;
use std::ffi::CString;

use crate::runtime::{Bool, Class, Imp, Object, Protocol, Sel};
Expand Down Expand Up @@ -137,7 +136,7 @@ unsafe impl Sync for ClassDecl {}
impl ClassDecl {
fn with_superclass(name: &str, superclass: Option<&Class>) -> Option<ClassDecl> {
let name = CString::new(name).unwrap();
let super_ptr = superclass.map_or(ptr::null(), |c| c) as _;
let super_ptr = superclass.map_or(0 as *const _, |c| c) as _;
let cls = unsafe { ffi::objc_allocateClassPair(super_ptr, name.as_ptr(), 0) };
if cls.is_null() {
None
Expand Down
4 changes: 2 additions & 2 deletions objc2/src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ extern "C" {
pub unsafe fn throw(exception: Option<&Id<Object, Shared>>) -> ! {
let exception = match exception {
Some(id) => &**id as *const Object as *mut ffi::objc_object,
None => ptr::null_mut(),
None => ptr::from_raw_parts_mut(ptr::null_mut(), ()),
};
unsafe { ffi::objc_exception_throw(exception) }
}
Expand All @@ -63,7 +63,7 @@ unsafe fn try_no_ret<F: FnOnce()>(closure: F) -> Result<(), Option<Id<Object, Sh
let mut closure = Some(closure);
let context = &mut closure as *mut _ as *mut c_void;

let mut exception = ptr::null_mut();
let mut exception = ptr::from_raw_parts_mut(ptr::null_mut(), ());
let success = unsafe { rust_objc_try_catch_exception(f, context, &mut exception) };

if success == 0 {
Expand Down
1 change: 1 addition & 0 deletions objc2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The bindings can be used on Linux or *BSD utilizing the
feature = "unstable_autoreleasesafe",
feature(negative_impls, auto_traits)
)]
#![cfg_attr(feature = "unstable_extern_types", feature(ptr_metadata))]
#![warn(elided_lifetimes_in_paths)]
#![warn(missing_docs)]
#![deny(non_ascii_idents)]
Expand Down
4 changes: 2 additions & 2 deletions objc2/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ mod tests {
#[cfg(not(feature = "verify_message"))]
#[test]
fn test_send_message_nil() {
let nil: *mut Object = ::core::ptr::null_mut();
let nil: *mut Object = 0 as *mut Object;

let result: *mut Object = unsafe { msg_send![nil, description] };
assert!(result.is_null());
Expand Down Expand Up @@ -447,7 +447,7 @@ mod tests {
};
assert_eq!(result, 4);

let obj: *const ManuallyDrop<Object> = (&**obj as *const Object).cast();
let obj = &**obj as *const Object as *const ManuallyDrop<Object>;
let result: u32 = unsafe { msg_send![obj, foo] };
assert_eq!(result, 4);
}
Expand Down
20 changes: 11 additions & 9 deletions objc2/src/rc/weak_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub struct WeakId<T: ?Sized> {
item: PhantomData<Id<T, Shared>>,
}

impl<T: Message> WeakId<T> {
impl<T: Message + ?Sized + ptr::Thin> WeakId<T> {
/// Construct a new [`WeakId`] referencing the given shared [`Id`].
#[doc(alias = "objc_initWeak")]
pub fn new(obj: &Id<T, Shared>) -> Self {
Expand All @@ -45,7 +45,8 @@ impl<T: Message> WeakId<T> {
///
/// The object must be valid or null.
unsafe fn new_inner(obj: *mut T) -> Self {
let inner = Box::new(UnsafeCell::new(ptr::null_mut()));
let null = ptr::from_raw_parts_mut(ptr::null_mut(), ());
let inner = Box::new(UnsafeCell::new(null));
// SAFETY: `ptr` will never move, and the caller verifies `obj`
let _ = unsafe { ffi::objc_initWeak(inner.get() as _, obj as _) };
Self {
Expand All @@ -64,7 +65,8 @@ impl<T: Message> WeakId<T> {
#[inline]
pub fn load(&self) -> Option<Id<T, Shared>> {
let ptr: *mut *mut ffi::objc_object = self.inner.get() as _;
let obj = unsafe { ffi::objc_loadWeakRetained(ptr) } as *mut T;
let obj = unsafe { ffi::objc_loadWeakRetained(ptr) } as *mut ();
let obj: *mut T = ptr::from_raw_parts_mut(obj, ());
NonNull::new(obj).map(|obj| unsafe { Id::new(obj) })
}
}
Expand All @@ -77,12 +79,12 @@ impl<T: ?Sized> Drop for WeakId<T> {
}
}

// TODO: Add ?Sized
impl<T> Clone for WeakId<T> {
impl<T: ?Sized + ptr::Thin> Clone for WeakId<T> {
/// Makes a clone of the `WeakId` that points to the same object.
#[doc(alias = "objc_copyWeak")]
fn clone(&self) -> Self {
let ptr = Box::new(UnsafeCell::new(ptr::null_mut()));
let null = ptr::from_raw_parts_mut(ptr::null_mut(), ());
let ptr = Box::new(UnsafeCell::new(null));
unsafe { ffi::objc_copyWeak(ptr.get() as _, self.inner.get() as _) };
Self {
inner: ptr,
Expand All @@ -91,14 +93,14 @@ impl<T> Clone for WeakId<T> {
}
}

// TODO: Add ?Sized
impl<T: Message> Default for WeakId<T> {
impl<T: Message + ?Sized + ptr::Thin> Default for WeakId<T> {
/// Constructs a new `WeakId<T>` that doesn't reference any object.
///
/// Calling [`Self::load`] on the return value always gives [`None`].
fn default() -> Self {
let null = ptr::from_raw_parts_mut(ptr::null_mut(), ());
// SAFETY: The pointer is null
unsafe { Self::new_inner(ptr::null_mut()) }
unsafe { Self::new_inner(null) }
}
}

Expand Down
2 changes: 1 addition & 1 deletion objc2/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ impl Class {
let name = CString::new(name).unwrap();
let ivar = unsafe { ffi::class_getClassVariable(self.as_ptr(), name.as_ptr()) };
// SAFETY: TODO
unsafe { ivar.cast::<Ivar>().as_ref() }
unsafe { (ivar as *const Ivar).as_ref() }
}

/// Describes the instance methods implemented by self.
Expand Down

0 comments on commit 7c496ce

Please sign in to comment.