Skip to content

Commit 2fb4fb8

Browse files
committed
Remove INSObject::new
Some classes (NSValue is the current example of this, but it's probably not the only case) don't want to handle cases where the users didn't supply a value, and implement `init` with throwing an exception or returning `nil`. We could panic in those cases (though we can't currently catch GNUStep exceptions), but instead we should just simply not provide a way to construct these invalid instances.
1 parent 9b8ce34 commit 2fb4fb8

File tree

11 files changed

+52
-71
lines changed

11 files changed

+52
-71
lines changed

objc2_foundation/examples/basic_usage.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use objc2::rc::autoreleasepool;
22
use objc2_foundation::{
3-
INSArray, INSCopying, INSDictionary, INSObject, INSString, NSArray, NSDictionary, NSObject,
4-
NSString,
3+
INSArray, INSCopying, INSDictionary, INSString, NSArray, NSDictionary, NSObject, NSString,
54
};
65

76
fn main() {

objc2_foundation/examples/class_with_lifetime.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ unsafe impl RefEncode for MyObject<'_> {
2424
unsafe impl Message for MyObject<'_> {}
2525

2626
impl<'a> MyObject<'a> {
27-
fn new_with_ptr(number_ptr: &'a mut u8) -> Id<Self, Owned> {
27+
fn new(number_ptr: &'a mut u8) -> Id<Self, Owned> {
2828
unsafe {
2929
let obj: *mut Self = msg_send![Self::class(), alloc];
3030
let obj: *mut Self = msg_send![obj, initWithPtr: number_ptr];
@@ -83,7 +83,7 @@ unsafe impl INSObject for MyObject<'_> {
8383

8484
fn main() {
8585
let mut number = 54;
86-
let mut obj = MyObject::new_with_ptr(&mut number);
86+
let mut obj = MyObject::new(&mut number);
8787

8888
println!("Number: {}", obj.get().unwrap());
8989

objc2_foundation/examples/custom_class.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
use std::ptr::NonNull;
12
use std::sync::Once;
23

34
use objc2::declare::ClassDecl;
4-
use objc2::rc::Owned;
5+
use objc2::rc::{Id, Owned};
56
use objc2::runtime::{Class, Object, Sel};
67
use objc2::{msg_send, sel};
78
use objc2::{Encoding, Message, RefEncode};
@@ -22,6 +23,11 @@ unsafe impl RefEncode for MYObject {
2223
}
2324

2425
impl MYObject {
26+
fn new() -> Id<Self, <Self as INSObject>::Ownership> {
27+
let cls = Self::class();
28+
unsafe { Id::new(NonNull::new_unchecked(msg_send![cls, new])) }
29+
}
30+
2531
fn number(&self) -> u32 {
2632
unsafe {
2733
let obj = &*(self as *const _ as *const Object);

objc2_foundation/src/array.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub unsafe trait INSArray: INSObject {
2929
type Item: INSObject;
3030
type ItemOwnership: Ownership;
3131

32+
unsafe_def_fn!(fn new);
33+
3234
#[doc(alias = "count")]
3335
fn len(&self) -> usize {
3436
unsafe { msg_send![self, count] }
@@ -387,7 +389,7 @@ mod tests {
387389
assert_eq!(array.first(), array.get(0));
388390
assert_eq!(array.last(), array.get(3));
389391

390-
let empty_array: Id<NSArray<NSObject, Owned>, _> = INSObject::new();
392+
let empty_array = <NSArray<NSObject, Owned>>::new();
391393
assert!(empty_array.first().is_none());
392394
assert!(empty_array.last().is_none());
393395
}

objc2_foundation/src/data.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use objc2::msg_send;
99
use objc2::rc::{Id, Owned, Shared};
1010

1111
pub unsafe trait INSData: INSObject {
12+
unsafe_def_fn!(fn new);
13+
1214
fn len(&self) -> usize {
1315
unsafe { msg_send![self, length] }
1416
}
@@ -179,7 +181,6 @@ impl DerefMut for NSMutableData {
179181
#[cfg(test)]
180182
mod tests {
181183
use super::{INSData, INSMutableData, NSData, NSMutableData};
182-
use crate::INSObject;
183184
#[cfg(feature = "block")]
184185
use alloc::vec;
185186

objc2_foundation/src/dictionary.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub unsafe trait INSDictionary: INSObject {
3232
type Value: INSObject;
3333
type ValueOwnership: Ownership;
3434

35+
unsafe_def_fn!(fn new);
36+
3537
#[doc(alias = "count")]
3638
fn len(&self) -> usize {
3739
unsafe { msg_send![self, count] }
@@ -169,7 +171,7 @@ mod tests {
169171
use objc2::rc::{autoreleasepool, Id, Shared};
170172

171173
use super::{INSDictionary, NSDictionary};
172-
use crate::{INSArray, INSObject, INSString, NSObject, NSString};
174+
use crate::{INSArray, INSString, NSObject, NSString};
173175

174176
fn sample_dict(key: &str) -> Id<NSDictionary<NSString, NSObject>, Shared> {
175177
let string = NSString::from_str(key);

objc2_foundation/src/enumerator.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -173,29 +173,25 @@ mod tests {
173173

174174
#[test]
175175
fn test_enumerator() {
176-
let vec = (0u32..4).map(NSValue::from_value).collect();
176+
let vec = (0u32..4).map(NSValue::new).collect();
177177
let array = NSArray::from_vec(vec);
178178

179179
let enumerator = array.object_enumerator();
180180
assert!(enumerator.count() == 4);
181181

182182
let enumerator = array.object_enumerator();
183-
assert!(enumerator
184-
.enumerate()
185-
.all(|(i, obj)| obj.get() == Some(i as u32)));
183+
assert!(enumerator.enumerate().all(|(i, obj)| obj.get() == i as u32));
186184
}
187185

188186
#[test]
189187
fn test_fast_enumerator() {
190-
let vec = (0u32..4).map(NSValue::from_value).collect();
188+
let vec = (0u32..4).map(NSValue::new).collect();
191189
let array = NSArray::from_vec(vec);
192190

193191
let enumerator = array.enumerator();
194192
assert!(enumerator.count() == 4);
195193

196194
let enumerator = array.enumerator();
197-
assert!(enumerator
198-
.enumerate()
199-
.all(|(i, obj)| obj.get() == Some(i as u32)));
195+
assert!(enumerator.enumerate().all(|(i, obj)| obj.get() == i as u32));
200196
}
201197
}

objc2_foundation/src/macros.rs

+9
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,12 @@ macro_rules! object_impl {
7575
}
7676
);
7777
}
78+
79+
macro_rules! unsafe_def_fn {
80+
($v:vis fn new) => {
81+
$v fn new() -> Id<Self, <Self as INSObject>::Ownership> {
82+
let cls = <Self as INSObject>::class();
83+
unsafe { Id::new(NonNull::new_unchecked(msg_send![cls, new])) }
84+
}
85+
};
86+
}

objc2_foundation/src/object.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,14 @@ pub unsafe trait INSObject: Sized + Message {
4747
let result: Bool = unsafe { msg_send![self, isKindOfClass: cls] };
4848
result.is_true()
4949
}
50-
51-
fn new() -> Id<Self, Self::Ownership> {
52-
let cls = Self::class();
53-
unsafe { Id::new(msg_send![cls, new]) }
54-
}
5550
}
5651

5752
object_struct!(unsafe NSObject, Owned);
5853

54+
impl NSObject {
55+
unsafe_def_fn!(pub fn new);
56+
}
57+
5958
#[cfg(test)]
6059
mod tests {
6160
use super::{INSObject, NSObject};

objc2_foundation/src/string.rs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const UTF8_ENCODING: usize = 4;
1717
const UTF8_ENCODING: i32 = 4;
1818

1919
pub unsafe trait INSString: INSObject {
20+
unsafe_def_fn!(fn new);
21+
2022
fn len(&self) -> usize {
2123
unsafe { msg_send![self, lengthOfBytesUsingEncoding: UTF8_ENCODING] }
2224
}

objc2_foundation/src/value.rs

+15-50
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@ use super::{INSCopying, INSObject};
1717
pub unsafe trait INSValue: INSObject {
1818
type Value: 'static + Copy + Encode;
1919

20+
// Default / empty new is not provided because `-init` returns `nil` on
21+
// Apple and GNUStep throws an exception on all other messages to this
22+
// invalid instance.
23+
2024
/// TODO.
21-
///
22-
/// If the value was created using [`INSObject::new`], the value may not
23-
/// be initialized. In that case, this will return [`None`].
24-
fn get(&self) -> Option<Self::Value> {
25-
// If encoding is `None`, this was created using INSObject::new
25+
fn get(&self) -> Self::Value {
2626
if let Some(encoding) = self.encoding() {
2727
// TODO: This can be a debug assertion (?)
28-
assert!(&Self::Value::ENCODING == encoding);
29-
Some(unsafe { self.get_unchecked() })
28+
assert!(&Self::Value::ENCODING == encoding, "Wrong encoding");
29+
unsafe { self.get_unchecked() }
3030
} else {
31-
None
31+
panic!("Missing NSValue encoding");
3232
}
3333
}
3434

@@ -44,7 +44,7 @@ pub unsafe trait INSValue: INSObject {
4444
result.map(|s| unsafe { CStr::from_ptr(s.as_ptr()) }.to_str().unwrap())
4545
}
4646

47-
fn from_value(value: Self::Value) -> Id<Self, Self::Ownership> {
47+
fn new(value: Self::Value) -> Id<Self, Self::Ownership> {
4848
let cls = Self::class();
4949
let bytes = &value as *const Self::Value as *const c_void;
5050
let encoding = CString::new(Self::Value::ENCODING.to_string()).unwrap();
@@ -70,31 +70,7 @@ unsafe impl<T: 'static> INSObject for NSValue<T> {
7070
type Ownership = Shared;
7171

7272
fn class() -> &'static Class {
73-
#[cfg(not(gnustep))]
74-
return class!(NSValue);
75-
76-
#[cfg(gnustep)]
77-
// We can't use NSValue directly, because its `new` method throws an
78-
// exception (instead of just becoming an invalid NSValue). Luckily,
79-
// the `GSValue` subclass has the desired behaviour, so we can just
80-
// use that. Unfortunately, this is less efficient for the following:
81-
// ```
82-
// match T::ENCODING {
83-
// Encoding::Object => ...,
84-
// Encoding::Struct("_NSPoint", _) => ...,
85-
// Encoding::Pointer(&Encoding::Void) => ...,
86-
// Encoding::Struct("_NSRange", _) => ...,
87-
// Encoding::Struct("_NSRect", _) => ...,
88-
// Encoding::Struct("_NSSize", _) => ...,
89-
// }
90-
// ```
91-
//
92-
// See GNUStep's `NSValue +valueClassWithObjCType` and
93-
// `GSConcreteValueTemplate.m` for more, though we can't use the
94-
// classes in there either, because their `new` methods return valid
95-
// objects (and so `<NSValue<NSRange>>::new()` would work differently
96-
// on GNUStep).
97-
return class!(GSValue);
73+
class!(NSValue)
9874
}
9975
}
10076

@@ -108,31 +84,20 @@ unsafe impl<T: 'static> INSCopying for NSValue<T> {
10884

10985
#[cfg(test)]
11086
mod tests {
111-
use crate::{INSObject, INSValue, NSRange, NSValue};
87+
use crate::{INSValue, NSRange, NSValue};
11288
use objc2::Encode;
11389

11490
#[test]
11591
fn test_value() {
116-
let val = NSValue::from_value(13u32);
117-
assert_eq!(val.get().unwrap(), 13);
92+
let val = NSValue::new(13u32);
93+
assert_eq!(val.get(), 13);
11894
assert!(&u32::ENCODING == val.encoding().unwrap());
11995
}
12096

121-
#[test]
122-
fn test_value_new() {
123-
let val = <NSValue<u8>>::new();
124-
assert!(val.encoding().is_none());
125-
assert!(val.get().is_none());
126-
}
127-
12897
#[test]
12998
fn test_value_nsrange() {
130-
let val = NSValue::from_value(NSRange::from(1..2));
99+
let val = NSValue::new(NSRange::from(1..2));
131100
assert!(&NSRange::ENCODING == val.encoding().unwrap());
132-
assert_eq!(val.get().unwrap(), NSRange::from(1..2));
133-
134-
let val = <NSValue<NSRange>>::new();
135-
assert!(val.encoding().is_none());
136-
assert!(val.get().is_none());
101+
assert_eq!(val.get(), NSRange::from(1..2));
137102
}
138103
}

0 commit comments

Comments
 (0)