Skip to content

Commit 6caf8aa

Browse files
authored
Merge pull request #254 from madsmtm/ivar-drop
Allow `Drop` types in ivars
2 parents b4c7c69 + 9eb1625 commit 6caf8aa

File tree

9 files changed

+702
-143
lines changed

9 files changed

+702
-143
lines changed

objc2/CHANGELOG.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88
## Unreleased - YYYY-MM-DD
99

1010
### Added
11-
* `Ivar::write`, `Ivar::as_ptr` and `Ivar::as_mut_ptr` for querying/modifying
12-
the instance variable inside `init` methods.
11+
* Added `Ivar::write`, `Ivar::as_ptr` and `Ivar::as_mut_ptr` for safely
12+
querying and modifying instance variables inside `init` methods.
13+
* Added `IvarDrop<T>` to allow storing complex `Drop` values in ivars
14+
(currently `rc::Id<T, O>`, `Box<T>`, `Option<rc::Id<T, O>>` or
15+
`Option<Box<T>>`).
1316

1417
### Removed
1518
* **BREAKING**: `MaybeUninit` no longer implements `IvarType` directly; use

objc2/examples/delegate.rs

+22-15
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#![cfg_attr(not(all(feature = "apple", target_os = "macos")), allow(unused))]
2-
use objc2::declare::Ivar;
3-
use objc2::foundation::NSObject;
2+
use objc2::declare::{Ivar, IvarDrop};
3+
use objc2::foundation::{NSCopying, NSObject, NSString};
44
use objc2::rc::{Id, Shared};
55
use objc2::runtime::Object;
6-
use objc2::{declare_class, extern_class, msg_send, msg_send_id, ClassType};
6+
use objc2::{declare_class, extern_class, msg_send, msg_send_id, ns_string, ClassType};
77

88
#[cfg(all(feature = "apple", target_os = "macos"))]
99
#[link(name = "AppKit", kind = "framework")]
@@ -23,6 +23,10 @@ declare_class!(
2323
struct CustomAppDelegate {
2424
pub ivar: u8,
2525
another_ivar: bool,
26+
box_ivar: IvarDrop<Box<i32>>,
27+
maybe_box_ivar: IvarDrop<Option<Box<i32>>>,
28+
id_ivar: IvarDrop<Id<NSString, Shared>>,
29+
maybe_id_ivar: IvarDrop<Option<Id<NSString, Shared>>>,
2630
}
2731

2832
unsafe impl ClassType for CustomAppDelegate {
@@ -34,18 +38,17 @@ declare_class!(
3438
#[sel(initWith:another:)]
3539
fn init_with(self: &mut Self, ivar: u8, another_ivar: bool) -> Option<&mut Self> {
3640
let this: Option<&mut Self> = unsafe { msg_send![super(self), init] };
41+
42+
// TODO: `ns_string` can't be used inside closures; investigate!
43+
let s = ns_string!("def");
44+
3745
this.map(|this| {
3846
Ivar::write(&mut this.ivar, ivar);
39-
Ivar::write(&mut this.another_ivar, another_ivar);
40-
// Note that we could have done this with just:
41-
// *this.ivar = ivar;
42-
// *this.another_ivar = another_ivar;
43-
//
44-
// Since these two ivar types (`u8` and `bool`) are safe to
45-
// initialize from all zeroes; but for this example, we chose
46-
// to be explicit.
47-
48-
// SAFETY: All the instance variables have been initialized
47+
*this.another_ivar = another_ivar;
48+
*this.maybe_box_ivar = None;
49+
*this.maybe_id_ivar = Some(s.copy());
50+
Ivar::write(&mut this.box_ivar, Box::new(2));
51+
Ivar::write(&mut this.id_ivar, NSString::from_str("abc"));
4952
this
5053
})
5154
}
@@ -97,8 +100,12 @@ impl CustomAppDelegate {
97100
fn main() {
98101
let delegate = CustomAppDelegate::new(42, true);
99102

100-
println!("{}", delegate.ivar);
101-
println!("{}", delegate.another_ivar);
103+
println!("{:?}", delegate.ivar);
104+
println!("{:?}", delegate.another_ivar);
105+
println!("{:?}", delegate.box_ivar);
106+
println!("{:?}", delegate.maybe_box_ivar);
107+
println!("{:?}", delegate.id_ivar);
108+
println!("{:?}", delegate.maybe_id_ivar);
102109
}
103110

104111
#[cfg(not(all(feature = "apple", target_os = "macos")))]

objc2/src/__macro_helpers.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub use core::mem::size_of;
1313
pub use core::ops::{Deref, DerefMut};
1414
pub use core::option::Option::{self, None, Some};
1515
pub use core::primitive::{bool, str, u8};
16+
pub use core::ptr::drop_in_place;
1617
pub use core::{compile_error, concat, panic, stringify};
1718
// TODO: Use `core::cell::LazyCell`
1819
pub use std::sync::Once;

objc2/src/declare.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
//! ```
113113
114114
mod ivar;
115+
mod ivar_drop;
115116
mod ivar_forwarding_impls;
116117

117118
use alloc::format;
@@ -122,13 +123,14 @@ use core::ptr;
122123
use core::ptr::NonNull;
123124
use std::ffi::CString;
124125

125-
use crate::encode::{Encode, EncodeArguments, EncodeConvert, Encoding, RefEncode};
126+
use crate::encode::{Encode, EncodeArguments, Encoding, RefEncode};
126127
use crate::ffi;
127128
use crate::runtime::{Bool, Class, Imp, Object, Protocol, Sel};
128129
use crate::sel;
129130
use crate::Message;
130131

131-
pub use ivar::{Ivar, IvarType};
132+
pub use ivar::{InnerIvarType, Ivar, IvarType};
133+
pub use ivar_drop::IvarDrop;
132134

133135
pub(crate) mod private {
134136
pub trait Sealed {}
@@ -410,12 +412,13 @@ impl ClassBuilder {
410412
/// If the ivar wasn't successfully added for some reason - this usually
411413
/// happens if there already was an ivar with that name.
412414
pub fn add_ivar<T: Encode>(&mut self, name: &str) {
413-
self.add_ivar_inner::<T>(name)
415+
// SAFETY: The encoding is correct
416+
unsafe { self.add_ivar_inner::<T>(name, &T::ENCODING) }
414417
}
415418

416-
fn add_ivar_inner<T: EncodeConvert>(&mut self, name: &str) {
419+
unsafe fn add_ivar_inner<T>(&mut self, name: &str, encoding: &Encoding) {
417420
let c_name = CString::new(name).unwrap();
418-
let encoding = CString::new(T::__ENCODING.to_string()).unwrap();
421+
let encoding = CString::new(encoding.to_string()).unwrap();
419422
let size = mem::size_of::<T>();
420423
let align = log2_align_of::<T>();
421424
let success = Bool::from_raw(unsafe {
@@ -437,7 +440,13 @@ impl ClassBuilder {
437440
///
438441
/// Same as [`ClassBuilder::add_ivar`].
439442
pub fn add_static_ivar<T: IvarType>(&mut self) {
440-
self.add_ivar_inner::<T::Type>(T::NAME)
443+
// SAFETY: The encoding is correct
444+
unsafe {
445+
self.add_ivar_inner::<<T::Type as InnerIvarType>::__Inner>(
446+
T::NAME,
447+
&T::Type::__ENCODING,
448+
)
449+
}
441450
}
442451

443452
/// Adds the given protocol to self.

0 commit comments

Comments
 (0)