Skip to content

Commit abf973e

Browse files
authored
Merge pull request #424 from madsmtm/redo-autorelease
Redo autorelease pools
2 parents d56f4ae + 4665c22 commit abf973e

File tree

15 files changed

+506
-293
lines changed

15 files changed

+506
-293
lines changed

crates/icrate/src/Foundation/additions/string.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![cfg(feature = "Foundation_NSString")]
2-
use alloc::borrow::ToOwned;
32
use core::cmp;
43
use core::ffi::c_void;
54
use core::fmt;
@@ -14,7 +13,7 @@ use core::str;
1413
use std::os::raw::c_char;
1514

1615
use objc2::msg_send;
17-
use objc2::rc::{autoreleasepool, AutoreleasePool, DefaultId, Id, Shared};
16+
use objc2::rc::{autoreleasepool_leaking, AutoreleasePool, DefaultId, Id, Shared};
1817
use objc2::runtime::__nsstring::{nsstring_len, nsstring_to_str, UTF8_ENCODING};
1918

2019
use crate::common::*;
@@ -110,7 +109,7 @@ impl NSString {
110109
///
111110
/// TODO: Further explain this.
112111
#[doc(alias = "UTF8String")]
113-
pub fn as_str<'r, 's: 'r, 'p: 'r>(&'s self, pool: &'p AutoreleasePool) -> &'r str {
112+
pub fn as_str<'r, 's: 'r, 'p: 'r>(&'s self, pool: AutoreleasePool<'p>) -> &'r str {
114113
// SAFETY: This is an instance of `NSString`
115114
unsafe { nsstring_to_str(self, pool) }
116115
}
@@ -180,20 +179,12 @@ impl DefaultId for NSString {
180179

181180
impl fmt::Display for NSString {
182181
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183-
// The call to `to_owned` is unfortunate, but is required to work
184-
// around `f` not being AutoreleaseSafe.
185-
// TODO: Fix this!
186-
let s = autoreleasepool(|pool| self.as_str(pool).to_owned());
187-
fmt::Display::fmt(&s, f)
182+
autoreleasepool_leaking(|pool| fmt::Display::fmt(self.as_str(pool), f))
188183
}
189184
}
190185

191186
impl fmt::Debug for NSString {
192187
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193-
// The call to `to_owned` is unfortunate, but is required to work
194-
// around `f` not being AutoreleaseSafe.
195-
// TODO: Fix this!
196-
let s = autoreleasepool(|pool| self.as_str(pool).to_owned());
197-
fmt::Debug::fmt(&s, f)
188+
autoreleasepool_leaking(|pool| fmt::Debug::fmt(self.as_str(pool), f))
198189
}
199190
}

crates/objc2/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## Unreleased - YYYY-MM-DD
88

9+
### Added
10+
* Added `objc2::rc::autoreleasepool_leaking`, and improve performance of
11+
objects `Debug` impls.
12+
913
### Changed
1014
* Made the default ownership in `Id` be `Shared`. This means that you can now
1115
write `Id<NSString>`, and it'll mean `Id<NSString, Shared>`.
16+
* **BREAKING**: `objc2::rc::AutoreleasePool` is now a zero-sized `Copy` type
17+
with a lifetime parameter, instead of the lifetime parameter being the
18+
reference it was behind.
19+
* **BREAKING**: Made `Id::autorelease` and `Id::autorelease_return` be
20+
associated functions instead of methods. This means they now have to be
21+
called as `Id::autorelease(obj, pool)` instead of `obj.autorelease(pool)`.
22+
23+
Additionally, rename the mutable version to `Id::autorelease_mut`.
24+
25+
### Fixed
26+
* Fixed using autorelease pools on 32bit macOS and older macOS versions.
1227

1328

1429
## 0.3.0-beta.5 - 2023-02-07

crates/objc2/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ unstable-static-sel-inlined = ["unstable-static-sel"]
5454
unstable-static-class = ["objc2-proc-macros"]
5555
unstable-static-class-inlined = ["unstable-static-class"]
5656

57-
# Uses nightly features to make AutoreleasePool zero-cost even in debug mode
57+
# Uses nightly features to make autorelease pools fully sound
5858
unstable-autoreleasesafe = []
5959

6060
# Uses the nightly c_unwind feature to make throwing safe

crates/objc2/src/declare.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
//! initWithNumber: number,
6161
//! ]
6262
//! };
63-
//! obj.map(|obj| obj.autorelease_return()).unwrap_or(std::ptr::null_mut())
63+
//! obj.map(Id::autorelease_return).unwrap_or(std::ptr::null_mut())
6464
//! }
6565
//! unsafe {
6666
//! builder.add_class_method(

crates/objc2/src/exception.rs

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
// TODO: Test this with panic=abort, and ensure that the code-size is
2020
// reasonable in that case.
2121

22-
use crate::alloc::borrow::ToOwned;
2322
#[cfg(feature = "exception")]
2423
use core::ffi::c_void;
2524
use core::fmt;
@@ -35,7 +34,7 @@ use std::error::Error;
3534
use crate::encode::{Encoding, RefEncode};
3635
#[cfg(feature = "exception")]
3736
use crate::ffi;
38-
use crate::rc::{autoreleasepool, Id};
37+
use crate::rc::{autoreleasepool_leaking, Id};
3938
use crate::runtime::__nsstring::nsstring_to_str;
4039
use crate::runtime::{Class, NSObject, NSObjectProtocol, Object};
4140
use crate::{extern_methods, sel, Message};
@@ -110,28 +109,27 @@ impl fmt::Debug for Exception {
110109
// Attempt to present a somewhat usable error message if the exception
111110
// is an instance of NSException.
112111
if let Some(true) = self.is_nsexception() {
113-
let (name, reason) = autoreleasepool(|pool| {
112+
autoreleasepool_leaking(|pool| {
114113
// SAFETY: Just checked that object is an NSException
115114
let (name, reason) = unsafe { (self.name(), self.reason()) };
116115

117116
// SAFETY: `name` and `reason` are guaranteed to be NSString.
118117
let name = name
119118
.as_deref()
120-
.map(|name| unsafe { nsstring_to_str(name, pool).to_owned() });
119+
.map(|name| unsafe { nsstring_to_str(name, pool) });
121120
let reason = reason
122121
.as_deref()
123-
.map(|reason| unsafe { nsstring_to_str(reason, pool).to_owned() });
124-
(name, reason)
125-
});
126-
127-
let obj: &Object = self.as_ref();
128-
write!(f, "{obj:?} '{}'", name.unwrap_or_default())?;
129-
if let Some(reason) = reason {
130-
write!(f, " reason:{reason}")?;
131-
} else {
132-
write!(f, " reason:(NULL)")?;
133-
}
134-
Ok(())
122+
.map(|reason| unsafe { nsstring_to_str(reason, pool) });
123+
124+
let obj: &Object = self.as_ref();
125+
write!(f, "{obj:?} '{}'", name.unwrap_or_default())?;
126+
if let Some(reason) = reason {
127+
write!(f, " reason:{reason}")?;
128+
} else {
129+
write!(f, " reason:(NULL)")?;
130+
}
131+
Ok(())
132+
})
135133
} else {
136134
// Fall back to `Object` Debug
137135
write!(f, "{:?}", self.0)
@@ -141,23 +139,20 @@ impl fmt::Debug for Exception {
141139

142140
impl fmt::Display for Exception {
143141
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144-
if let Some(true) = self.is_nsexception() {
145-
let reason = autoreleasepool(|pool| {
142+
autoreleasepool_leaking(|pool| {
143+
if let Some(true) = self.is_nsexception() {
146144
// SAFETY: Just checked that object is an NSException
147145
let reason = unsafe { self.reason() };
148146

149-
// SAFETY: `reason` is guaranteed to be NSString.
150-
reason
151-
.as_deref()
152-
.map(|reason| unsafe { nsstring_to_str(reason, pool).to_owned() })
153-
});
154-
155-
if let Some(reason) = reason {
156-
return write!(f, "{reason}");
147+
if let Some(reason) = &reason {
148+
// SAFETY: `reason` is guaranteed to be NSString.
149+
let reason = unsafe { nsstring_to_str(reason, pool) };
150+
return write!(f, "{reason}");
151+
}
157152
}
158-
}
159153

160-
write!(f, "unknown exception")
154+
write!(f, "unknown exception")
155+
})
161156
}
162157
}
163158

crates/objc2/src/protocol.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
use alloc::borrow::ToOwned;
21
use core::fmt;
32
use core::hash;
43
use core::marker::PhantomData;
54
use core::ptr::NonNull;
65

76
use crate::encode::{Encoding, RefEncode};
8-
use crate::rc::{autoreleasepool, Id, Ownership};
7+
use crate::rc::{autoreleasepool_leaking, Id, Ownership};
98
use crate::runtime::__nsstring::nsstring_to_str;
109
use crate::runtime::{NSObjectProtocol, Object, Protocol};
1110
use crate::Message;
@@ -212,16 +211,17 @@ impl<P: ?Sized + ProtocolType + NSObjectProtocol> fmt::Debug for ProtocolObject<
212211
match description {
213212
// Attempt to format description string
214213
Some(description) => {
215-
let s = autoreleasepool(|pool| {
214+
// We use a leaking autorelease pool since often the string
215+
// will be UTF-8, and in that case the pool will be
216+
// irrelevant. Also, it allows us to pass the formatter into
217+
// the pool (since it may contain a pool internally that it
218+
// assumes is current when writing).
219+
autoreleasepool_leaking(|pool| {
216220
// SAFETY: `description` selector is guaranteed to always
217221
// return an instance of `NSString`.
218222
let s = unsafe { nsstring_to_str(&description, pool) };
219-
// The call to `to_owned` is unfortunate, but is required
220-
// to work around `f` not being `AutoreleaseSafe`.
221-
// TODO: Fix this!
222-
s.to_owned()
223-
});
224-
fmt::Display::fmt(&s, f)
223+
fmt::Display::fmt(s, f)
224+
})
225225
}
226226
// If description was `NULL`, use `Object`'s `Debug` impl instead
227227
None => {

0 commit comments

Comments
 (0)