Skip to content

Commit 3a53d3e

Browse files
authored
Merge pull request #110 from madsmtm/take-inspiration
Take inspiration from `objrs`
2 parents 63aba2e + 3e04a72 commit 3a53d3e

File tree

7 files changed

+103
-3
lines changed

7 files changed

+103
-3
lines changed

objc2-encode/src/encode.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ pub unsafe trait RefEncode {
147147
const ENCODING_REF: Encoding<'static>;
148148
}
149149

150+
// TODO: Implement for `PhantomData` and `PhantomPinned`?
151+
150152
/// Simple helper for implementing [`Encode`].
151153
macro_rules! encode_impls {
152154
($($t:ty => $e:ident,)*) => ($(
@@ -169,6 +171,8 @@ encode_impls!(
169171
f64 => Double,
170172
);
171173

174+
// TODO: Structs in core::arch?
175+
172176
/// To allow usage as the return type of generic functions.
173177
///
174178
/// You should not rely on this encoding to exist for any other purpose (since
@@ -304,6 +308,20 @@ unsafe impl<T: RefEncode + ?Sized> RefEncode for ManuallyDrop<T> {
304308
const ENCODING_REF: Encoding<'static> = T::ENCODING_REF;
305309
}
306310

311+
// TODO: Consider UnsafeCell<T>
312+
// It is #[repr(transparent)], but might not be safe given that UnsafeCell
313+
// also has #[repr(no_niche)]
314+
315+
// TODO: Consider Cell<T>
316+
// It is #[repr(transparent)] of UnsafeCell<T>, so figure that out first
317+
// `Cell` might also have other requirements that would disourage this impl?
318+
319+
// TODO: Types that need to be made repr(transparent) first:
320+
// core::cell::Ref?
321+
// core::cell::RefCell?
322+
// core::cell::RefMut?
323+
// core::panic::AssertUnwindSafe<T>
324+
307325
// SAFETY: `Pin` is `repr(transparent)`.
308326
unsafe impl<T: Encode> Encode for Pin<T> {
309327
const ENCODING: Encoding<'static> = T::ENCODING;
@@ -314,6 +332,8 @@ unsafe impl<T: RefEncode> RefEncode for Pin<T> {
314332
const ENCODING_REF: Encoding<'static> = T::ENCODING_REF;
315333
}
316334

335+
// TODO: MaybeUninit<T>
336+
317337
// SAFETY: `Wrapping` is `repr(transparent)`.
318338
unsafe impl<T: Encode> Encode for Wrapping<T> {
319339
const ENCODING: Encoding<'static> = T::ENCODING;
@@ -324,6 +344,10 @@ unsafe impl<T: RefEncode> RefEncode for Wrapping<T> {
324344
const ENCODING_REF: Encoding<'static> = T::ENCODING_REF;
325345
}
326346

347+
// TODO: core::num::Saturating when that is stabilized
348+
349+
// TODO: core::cmp::Reverse?
350+
327351
/// Helper for implementing `Encode`/`RefEncode` for pointers to types that
328352
/// implement `RefEncode`.
329353
///

objc2-encode/src/encoding.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ pub enum Encoding<'a> {
4242
/// A C `int`. Corresponds to the `i` code.
4343
Int,
4444
/// A C `long`. Corresponds to the `l` code.
45+
///
46+
/// This is treated as a 32-bit quantity in 64-bit programs.
47+
// TODO: What does that mean??
4548
Long,
4649
/// A C `long long`. Corresponds to the `q` code.
4750
LongLong,
@@ -121,6 +124,13 @@ pub enum Encoding<'a> {
121124
// } x_t;
122125
// NSLog(@"Encoding: %s", @encode(_Atomic x_t)); // -> A{x}
123126
// NSLog(@"Encoding: %s", @encode(const int*)); // -> r^i
127+
//
128+
// Note that const only applies to the outermost pointer!
129+
//
130+
// And how does atomic objects work?
131+
// core::sync::atomic::AtomicPtr<T: Message>?
132+
133+
// TODO: `t` and `T` codes for i128 and u128?
124134
}
125135

126136
impl Encoding<'_> {

objc2/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
99
### Added
1010
* Added deprecated `Object::get_ivar` and `Object::get_mut_ivar` to make
1111
upgrading easier.
12+
* Allow using `From`/`TryFrom` to convert between `rc::Id` and `rc::WeakId`.
1213

1314

1415
## 0.3.0-alpha.6 - 2022-01-03

objc2/src/exception.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
//! - <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Exceptions.html>
1515
//! - <https://llvm.org/docs/ExceptionHandling.html>
1616
17+
// TODO: Test this with panic=abort, and ensure that the code-size is
18+
// reasonable in that case.
19+
1720
use core::ffi::c_void;
1821
use core::mem;
1922
use core::ptr;
@@ -25,6 +28,21 @@ use crate::rc::{Id, Shared};
2528
use crate::runtime::Object;
2629

2730
extern "C" {
31+
/// Call the given function inside an Objective-C `@try/@catch` block.
32+
///
33+
/// Defined in `extern/exception.m` and compiled in `build.rs`.
34+
///
35+
/// Alternatively, we could manually write assembly for this function like
36+
/// [`objrs` does][manual-asm] does, that would cut down on a build stage
37+
/// (and would probably give us a bit better performance), but it gets
38+
/// unwieldy _very_ quickly, so I chose the much more stable option.
39+
///
40+
/// Another thing to remember: While Rust's and Objective-C's unwinding
41+
/// mechanisms are similar now, Rust's is explicitly unspecified, and they
42+
/// may diverge significantly in the future; so handling this in pure Rust
43+
/// (using mechanisms like core::intrinsics::r#try) is not an option!
44+
///
45+
/// [manual-asm]: https://gitlab.com/objrs/objrs/-/blob/b4f6598696b3fa622e6fddce7aff281770b0a8c2/src/exception.rs
2846
fn rust_objc_try_catch_exception(
2947
f: extern "C" fn(*mut c_void),
3048
context: *mut c_void,

objc2/src/rc/autorelease.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ use crate::ffi;
1818
/// pool on the current thread.
1919
#[derive(Debug)]
2020
pub struct AutoreleasePool {
21+
/// This is an opaque handle, and is not guaranteed to be neither a valid
22+
/// nor aligned pointer.
2123
context: *mut c_void,
2224
// May pointer to data that is mutated (even though we hold shared access)
2325
p: PhantomData<*mut UnsafeCell<c_void>>,
@@ -140,9 +142,13 @@ impl Drop for AutoreleasePool {
140142
/// > Not draining the pool during an unwind is apparently required by the
141143
/// > Objective-C exceptions implementation.
142144
///
143-
/// This was true in the past, but since [revision `371`] of objc4 (ships
144-
/// with MacOS 10.5) the exception is now retained when `@throw` is
145-
/// encountered.
145+
/// However, we would like to do this anyway whenever possible, since the
146+
/// unwind is probably caused by Rust, and forgetting to pop the pool will
147+
/// likely leak memory.
148+
///
149+
/// Fortunately, the above statement was true in the past, but since
150+
/// [revision `371`] of objc4 (ships with MacOS 10.5) the exception is now
151+
/// retained when `@throw` is encountered.
146152
///
147153
/// Hence it is safe to drain the pool when unwinding.
148154
///

objc2/src/rc/weak_id.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use alloc::boxed::Box;
22
use core::cell::UnsafeCell;
3+
use core::convert::TryFrom;
34
use core::fmt;
45
use core::marker::PhantomData;
56
use core::ptr;
@@ -24,6 +25,7 @@ pub struct WeakId<T: ?Sized> {
2425
/// an UnsafeCell to get a *mut without self being mutable.
2526
///
2627
/// TODO: Verify the need for UnsafeCell?
28+
/// TODO: Investigate if we can avoid some allocations using `Pin`.
2729
inner: Box<UnsafeCell<*mut T>>,
2830
/// WeakId inherits variance, dropck and various marker traits from
2931
/// `Id<T, Shared>` because it can be upgraded to a shared Id.
@@ -59,6 +61,7 @@ impl<T: Message> WeakId<T> {
5961
/// Returns [`None`] if the object has been deallocated or was created
6062
/// with [`Default::default`].
6163
#[doc(alias = "upgrade")]
64+
#[doc(alias = "retain")]
6265
#[doc(alias = "objc_loadWeak")]
6366
#[doc(alias = "objc_loadWeakRetained")]
6467
#[inline]
@@ -67,6 +70,8 @@ impl<T: Message> WeakId<T> {
6770
let obj = unsafe { ffi::objc_loadWeakRetained(ptr) } as *mut T;
6871
NonNull::new(obj).map(|obj| unsafe { Id::new(obj) })
6972
}
73+
74+
// TODO: Add `autorelease(&self) -> Option<&T>` using `objc_loadWeak`?
7075
}
7176

7277
impl<T: ?Sized> Drop for WeakId<T> {
@@ -124,6 +129,19 @@ impl<T: RefUnwindSafe + ?Sized> RefUnwindSafe for WeakId<T> {}
124129
// Same as `Id<T, Shared>`.
125130
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for WeakId<T> {}
126131

132+
impl<T: Message> From<Id<T, Shared>> for WeakId<T> {
133+
fn from(obj: Id<T, Shared>) -> Self {
134+
WeakId::new(&obj)
135+
}
136+
}
137+
138+
impl<T: Message> TryFrom<WeakId<T>> for Id<T, Shared> {
139+
type Error = ();
140+
fn try_from(weak: WeakId<T>) -> Result<Self, ()> {
141+
return weak.load().ok_or(());
142+
}
143+
}
144+
127145
#[cfg(test)]
128146
mod tests {
129147
use core::ptr::NonNull;

objc2/src/runtime.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,29 @@ mod tests {
649649
use crate::test_utils;
650650
use crate::Encode;
651651

652+
#[test]
653+
fn test_selector() {
654+
macro_rules! test_sel {
655+
($s:literal, $($tt:tt)+) => {{
656+
let sel = sel!($($tt)*);
657+
let expected = Sel::register($s);
658+
assert_eq!(sel, expected);
659+
assert_eq!(sel.name(), $s);
660+
}}
661+
}
662+
test_sel!("abc", abc);
663+
test_sel!("abc:", abc:);
664+
test_sel!("abc:def:", abc:def:);
665+
}
666+
667+
#[test]
668+
fn test_empty_selector() {
669+
let sel = Sel::register("");
670+
assert_eq!(sel.name(), "");
671+
let sel = Sel::register(":");
672+
assert_eq!(sel.name(), ":");
673+
}
674+
652675
#[test]
653676
fn test_ivar() {
654677
let cls = test_utils::custom_class();

0 commit comments

Comments
 (0)