Skip to content

Commit b64dc12

Browse files
committed
Make objc2-foundation work with unsized types
1 parent 794ff0d commit b64dc12

File tree

8 files changed

+66
-58
lines changed

8 files changed

+66
-58
lines changed

objc2-foundation/CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1616
### Changed
1717
* **BREAKING**: Made some creation methods a bit less generic (e.g.
1818
`INSDictionary::from_keys_and_objects` now always returns `Id<_, Shared>`).
19-
* Relax bounds on generic `INSObject` impls.
19+
* Relaxed bounds on generic `INSObject` impls.
20+
* Relaxed `Sized` bounds on generic objects like `NSArray`.
2021

2122
### Removed
2223
* **BREAKING**: Removed associated `Ownership` type from `INSObject`; instead,

objc2-foundation/src/array.rs

+25-25
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ unsafe fn from_refs<A: INSArray + ?Sized>(refs: &[&A::Item]) -> Id<A, A::Ownersh
3030

3131
pub unsafe trait INSArray: INSObject {
3232
type Ownership: Ownership;
33-
type Item: INSObject;
33+
type Item: INSObject + ?Sized;
3434
type ItemOwnership: Ownership;
3535

3636
unsafe_def_fn!(fn new -> Self::Ownership);
@@ -169,7 +169,7 @@ object!(
169169
/// TODO: Can we make it impossible? Should we?
170170
///
171171
/// What about `Id<NSArray<T, Shared>, Owned>`?
172-
unsafe pub struct NSArray<T, O: Ownership> {
172+
unsafe pub struct NSArray<T: ?Sized, O: Ownership> {
173173
item: PhantomData<Id<T, O>>,
174174
}
175175
);
@@ -179,22 +179,22 @@ object!(
179179
// The `PhantomData` can't get these impls to display in the docs.
180180
//
181181
// TODO: Properly verify this
182-
unsafe impl<T: Sync + Send> Sync for NSArray<T, Shared> {}
183-
unsafe impl<T: Sync + Send> Send for NSArray<T, Shared> {}
184-
unsafe impl<T: Sync> Sync for NSArray<T, Owned> {}
185-
unsafe impl<T: Send> Send for NSArray<T, Owned> {}
182+
unsafe impl<T: Sync + Send + ?Sized> Sync for NSArray<T, Shared> {}
183+
unsafe impl<T: Sync + Send + ?Sized> Send for NSArray<T, Shared> {}
184+
unsafe impl<T: Sync + ?Sized> Sync for NSArray<T, Owned> {}
185+
unsafe impl<T: Send + ?Sized> Send for NSArray<T, Owned> {}
186186

187187
/// ```compile_fail
188188
/// use objc2::rc::Shared;
189189
/// use objc2::runtime::Object;
190190
/// use objc2_foundation::NSArray;
191-
/// fn needs_send_sync<T: Send + Sync>() {}
191+
/// fn needs_send_sync<T: Send + Sync + ?Sized>() {}
192192
/// needs_send_sync::<NSArray<Object, Shared>>();
193193
/// ```
194194
#[cfg(doctest)]
195195
pub struct NSArrayWithObjectNotSendSync;
196196

197-
unsafe impl<T: INSObject, O: Ownership> INSArray for NSArray<T, O> {
197+
unsafe impl<T: INSObject + ?Sized, O: Ownership> INSArray for NSArray<T, O> {
198198
/// The `NSArray` itself (length and number of items) is always immutable,
199199
/// but we would like to know when we're the only owner of the array, to
200200
/// allow mutation of the array's items.
@@ -208,20 +208,20 @@ unsafe impl<T: INSObject, O: Ownership> INSArray for NSArray<T, O> {
208208

209209
// Copying only possible when ItemOwnership = Shared
210210

211-
unsafe impl<T: INSObject> INSCopying for NSArray<T, Shared> {
211+
unsafe impl<T: INSObject + ?Sized> INSCopying for NSArray<T, Shared> {
212212
type Ownership = Shared;
213213
type Output = NSArray<T, Shared>;
214214
}
215215

216-
unsafe impl<T: INSObject> INSMutableCopying for NSArray<T, Shared> {
216+
unsafe impl<T: INSObject + ?Sized> INSMutableCopying for NSArray<T, Shared> {
217217
type Output = NSMutableArray<T, Shared>;
218218
}
219219

220-
unsafe impl<T: INSObject, O: Ownership> INSFastEnumeration for NSArray<T, O> {
220+
unsafe impl<T: INSObject + ?Sized, O: Ownership> INSFastEnumeration for NSArray<T, O> {
221221
type Item = T;
222222
}
223223

224-
impl<T: INSObject, O: Ownership> Index<usize> for NSArray<T, O> {
224+
impl<T: INSObject + ?Sized, O: Ownership> Index<usize> for NSArray<T, O> {
225225
type Output = T;
226226

227227
fn index(&self, index: usize) -> &T {
@@ -306,7 +306,7 @@ pub unsafe trait INSMutableArray: INSArray {
306306
where
307307
F: FnMut(&Self::Item, &Self::Item) -> Ordering,
308308
{
309-
extern "C" fn compare_with_closure<T, F: FnMut(&T, &T) -> Ordering>(
309+
extern "C" fn compare_with_closure<T: ?Sized, F: FnMut(&T, &T) -> Ordering>(
310310
obj1: &T,
311311
obj2: &T,
312312
context: *mut c_void,
@@ -334,43 +334,43 @@ pub unsafe trait INSMutableArray: INSArray {
334334
}
335335

336336
object!(
337-
unsafe pub struct NSMutableArray<T, O: Ownership> {
337+
unsafe pub struct NSMutableArray<T: ?Sized, O: Ownership> {
338338
item: PhantomData<Id<T, O>>,
339339
}
340340
);
341341

342342
// SAFETY: Same as NSArray.
343343
//
344344
// TODO: Properly verify this
345-
unsafe impl<T: Sync + Send> Sync for NSMutableArray<T, Shared> {}
346-
unsafe impl<T: Sync + Send> Send for NSMutableArray<T, Shared> {}
347-
unsafe impl<T: Sync> Sync for NSMutableArray<T, Owned> {}
348-
unsafe impl<T: Send> Send for NSMutableArray<T, Owned> {}
345+
unsafe impl<T: Sync + Send + ?Sized> Sync for NSMutableArray<T, Shared> {}
346+
unsafe impl<T: Sync + Send + ?Sized> Send for NSMutableArray<T, Shared> {}
347+
unsafe impl<T: Sync + ?Sized> Sync for NSMutableArray<T, Owned> {}
348+
unsafe impl<T: Send + ?Sized> Send for NSMutableArray<T, Owned> {}
349349

350-
unsafe impl<T: INSObject, O: Ownership> INSArray for NSMutableArray<T, O> {
350+
unsafe impl<T: INSObject + ?Sized, O: Ownership> INSArray for NSMutableArray<T, O> {
351351
type Ownership = Owned;
352352
type Item = T;
353353
type ItemOwnership = O;
354354
}
355355

356-
unsafe impl<T: INSObject, O: Ownership> INSMutableArray for NSMutableArray<T, O> {}
356+
unsafe impl<T: INSObject + ?Sized, O: Ownership> INSMutableArray for NSMutableArray<T, O> {}
357357

358358
// Copying only possible when ItemOwnership = Shared
359359

360-
unsafe impl<T: INSObject> INSCopying for NSMutableArray<T, Shared> {
360+
unsafe impl<T: INSObject + ?Sized> INSCopying for NSMutableArray<T, Shared> {
361361
type Ownership = Shared;
362362
type Output = NSArray<T, Shared>;
363363
}
364364

365-
unsafe impl<T: INSObject> INSMutableCopying for NSMutableArray<T, Shared> {
365+
unsafe impl<T: INSObject + ?Sized> INSMutableCopying for NSMutableArray<T, Shared> {
366366
type Output = NSMutableArray<T, Shared>;
367367
}
368368

369-
unsafe impl<T: INSObject, O: Ownership> INSFastEnumeration for NSMutableArray<T, O> {
369+
unsafe impl<T: INSObject + ?Sized, O: Ownership> INSFastEnumeration for NSMutableArray<T, O> {
370370
type Item = T;
371371
}
372372

373-
impl<T: INSObject, O: Ownership> Index<usize> for NSMutableArray<T, O> {
373+
impl<T: INSObject + ?Sized, O: Ownership> Index<usize> for NSMutableArray<T, O> {
374374
type Output = T;
375375

376376
fn index(&self, index: usize) -> &T {
@@ -571,7 +571,7 @@ mod tests {
571571

572572
#[test]
573573
fn test_send_sync() {
574-
fn assert_send_sync<T: Send + Sync>() {}
574+
fn assert_send_sync<T: Send + Sync + ?Sized>() {}
575575

576576
assert_send_sync::<NSArray<NSString, Shared>>();
577577
assert_send_sync::<NSMutableArray<NSString, Shared>>();

objc2-foundation/src/copying.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub unsafe trait INSCopying: INSObject {
3232
///
3333
/// This is usually `Self`, but e.g. `NSMutableString` returns `NSString`.
3434
/// TODO: Verify???
35-
type Output: INSObject;
35+
type Output: INSObject + ?Sized;
3636

3737
fn copy(&self) -> Id<Self::Output, Self::Ownership> {
3838
unsafe {
@@ -47,7 +47,7 @@ pub unsafe trait INSCopying: INSObject {
4747
/// Note that the `mutableCopy` selector must return an owned object!
4848
pub unsafe trait INSMutableCopying: INSObject {
4949
/// TODO
50-
type Output: INSObject;
50+
type Output: INSObject + ?Sized;
5151

5252
fn mutable_copy(&self) -> Id<Self::Output, Owned> {
5353
unsafe {

objc2-foundation/src/dictionary.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ where
3030
}
3131

3232
pub unsafe trait INSDictionary: INSObject {
33-
type Key: INSObject;
34-
type Value: INSObject;
33+
type Key: INSObject + ?Sized;
34+
type Value: INSObject + ?Sized;
3535
type ValueOwnership: Ownership;
3636

3737
#[doc(alias = "count")]
@@ -139,31 +139,33 @@ pub unsafe trait INSDictionary: INSObject {
139139
}
140140

141141
object!(
142-
unsafe pub struct NSDictionary<K, V> {
142+
unsafe pub struct NSDictionary<K: ?Sized, V: ?Sized> {
143143
key: PhantomData<Id<K, Shared>>,
144144
obj: PhantomData<Id<V, Owned>>,
145145
}
146146
);
147147

148148
// TODO: SAFETY
149-
unsafe impl<K: Sync + Send, V: Sync> Sync for NSDictionary<K, V> {}
150-
unsafe impl<K: Sync + Send, V: Send> Send for NSDictionary<K, V> {}
149+
unsafe impl<K: Sync + Send + ?Sized, V: Sync + ?Sized> Sync for NSDictionary<K, V> {}
150+
unsafe impl<K: Sync + Send + ?Sized, V: Send + ?Sized> Send for NSDictionary<K, V> {}
151151

152-
impl<K: INSObject, V: INSObject> NSDictionary<K, V> {
152+
impl<K: INSObject + ?Sized, V: INSObject + ?Sized> NSDictionary<K, V> {
153153
unsafe_def_fn!(pub fn new -> Shared);
154154
}
155155

156-
unsafe impl<K: INSObject, V: INSObject> INSDictionary for NSDictionary<K, V> {
156+
unsafe impl<K: INSObject + ?Sized, V: INSObject + ?Sized> INSDictionary for NSDictionary<K, V> {
157157
type Key = K;
158158
type Value = V;
159159
type ValueOwnership = Owned;
160160
}
161161

162-
unsafe impl<K: INSObject, V: INSObject> INSFastEnumeration for NSDictionary<K, V> {
162+
unsafe impl<K: INSObject + ?Sized, V: INSObject + ?Sized> INSFastEnumeration
163+
for NSDictionary<K, V>
164+
{
163165
type Item = K;
164166
}
165167

166-
impl<'a, K: INSObject, V: INSObject> Index<&'a K> for NSDictionary<K, V> {
168+
impl<'a, K: INSObject + ?Sized, V: INSObject + ?Sized> Index<&'a K> for NSDictionary<K, V> {
167169
type Output = V;
168170

169171
fn index(&self, index: &K) -> &V {

objc2-foundation/src/enumerator.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ use objc2::{msg_send, Encode, Encoding, RefEncode};
1212

1313
use super::INSObject;
1414

15-
pub struct NSEnumerator<'a, T: INSObject> {
15+
pub struct NSEnumerator<'a, T: INSObject + ?Sized> {
1616
id: Id<Object, Owned>,
1717
item: PhantomData<&'a T>,
1818
}
1919

20-
impl<'a, T: INSObject> NSEnumerator<'a, T> {
20+
impl<'a, T: INSObject + ?Sized> NSEnumerator<'a, T> {
2121
/// TODO
2222
///
2323
/// # Safety
@@ -33,7 +33,7 @@ impl<'a, T: INSObject> NSEnumerator<'a, T> {
3333
}
3434
}
3535

36-
impl<'a, T: INSObject> Iterator for NSEnumerator<'a, T> {
36+
impl<'a, T: INSObject + ?Sized> Iterator for NSEnumerator<'a, T> {
3737
type Item = &'a T;
3838

3939
fn next(&mut self) -> Option<&'a T> {
@@ -42,15 +42,15 @@ impl<'a, T: INSObject> Iterator for NSEnumerator<'a, T> {
4242
}
4343

4444
pub unsafe trait INSFastEnumeration: INSObject {
45-
type Item: INSObject;
45+
type Item: INSObject + ?Sized;
4646

4747
fn enumerator(&self) -> NSFastEnumerator<'_, Self> {
4848
NSFastEnumerator::new(self)
4949
}
5050
}
5151

5252
#[repr(C)]
53-
struct NSFastEnumerationState<T: INSObject> {
53+
struct NSFastEnumerationState<T: INSObject + ?Sized> {
5454
state: c_ulong, // TODO: Verify this is actually always 64 bit
5555
items_ptr: *const *const T,
5656
mutations_ptr: *mut c_ulong,
@@ -78,7 +78,7 @@ const U_LONG_ENCODING: Encoding<'static> = {
7878
}
7979
};
8080

81-
unsafe impl<T: INSObject> Encode for NSFastEnumerationState<T> {
81+
unsafe impl<T: INSObject + ?Sized> Encode for NSFastEnumerationState<T> {
8282
const ENCODING: Encoding<'static> = Encoding::Struct(
8383
"?",
8484
&[
@@ -90,7 +90,7 @@ unsafe impl<T: INSObject> Encode for NSFastEnumerationState<T> {
9090
);
9191
}
9292

93-
unsafe impl<T: INSObject> RefEncode for NSFastEnumerationState<T> {
93+
unsafe impl<T: INSObject + ?Sized> RefEncode for NSFastEnumerationState<T> {
9494
const ENCODING_REF: Encoding<'static> = Encoding::Pointer(&Self::ENCODING);
9595
}
9696

@@ -131,14 +131,19 @@ pub struct NSFastEnumerator<'a, C: 'a + INSFastEnumeration + ?Sized> {
131131

132132
impl<'a, C: INSFastEnumeration + ?Sized> NSFastEnumerator<'a, C> {
133133
fn new(object: &'a C) -> Self {
134+
// SAFETY: C::Item is ?Sized, but it should always be a thin pointer.
135+
// This is just a way to get a null pointer because we can't apply the
136+
// correct ptr::Thin bound yet.
137+
let null_ptr = unsafe { mem::zeroed::<*const C::Item>() };
134138
Self {
135139
object,
136140

137141
ptr: ptr::null(),
138142
end: ptr::null(),
139143

140144
state: unsafe { mem::zeroed() },
141-
buf: [ptr::null(); FAST_ENUM_BUF_SIZE],
145+
// SAFETY:
146+
buf: [null_ptr; FAST_ENUM_BUF_SIZE],
142147
}
143148
}
144149

objc2-foundation/src/macros.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,25 @@ macro_rules! object {
1515
};
1616
(
1717
$(#[$m:meta])*
18-
unsafe $v:vis struct $name:ident<$($t:ident $(: $b:ident)?),*> {
18+
unsafe $v:vis struct $name:ident<$($t:ident $(: $b:ident)? $(: ?$sized:ident)?),*> {
1919
$($p:ident: $pty:ty,)*
2020
}
2121
) => {
2222
// TODO: `extern type`
2323
$(#[$m])*
2424
#[repr(C)]
25-
$v struct $name<$($t $(: $b)?),*> {
25+
$v struct $name<$($t $(: $b)? $(: ?$sized)?),*> {
2626
_private: [u8; 0],
2727
$($p: $pty),*
2828
}
2929

30-
unsafe impl<$($t $(: $b)?),*> ::objc2::Message for $name<$($t),*> { }
30+
unsafe impl<$($t $(: $b)? $(: ?$sized)?),*> ::objc2::Message for $name<$($t),*> { }
3131

32-
unsafe impl<$($t $(: $b)?),*> ::objc2::RefEncode for $name<$($t),*> {
32+
unsafe impl<$($t $(: $b)? $(: ?$sized)?),*> ::objc2::RefEncode for $name<$($t),*> {
3333
const ENCODING_REF: ::objc2::Encoding<'static> = ::objc2::Encoding::Object;
3434
}
3535

36-
unsafe impl<$($t $(: $b)?),*> $crate::INSObject for $name<$($t),*> {
36+
unsafe impl<$($t $(: $b)? $(: ?$sized)?),*> $crate::INSObject for $name<$($t),*> {
3737
fn class() -> &'static ::objc2::runtime::Class {
3838
::objc2::class!($name)
3939
}
@@ -49,7 +49,7 @@ macro_rules! object {
4949
// (instead of shallow) equality comparisons.
5050
//
5151
// See also https://nshipster.com/equality/
52-
impl<$($t: ::core::cmp::PartialEq $(+ $b)?),*> ::core::cmp::PartialEq for $name<$($t),*> {
52+
impl<$($t: ::core::cmp::PartialEq $(+ $b)? $(+ ?$sized)?),*> ::core::cmp::PartialEq for $name<$($t),*> {
5353
#[inline]
5454
fn eq(&self, other: &Self) -> bool {
5555
use $crate::INSObject;
@@ -61,15 +61,15 @@ macro_rules! object {
6161
//
6262
// `T: Eq` bound added to prevent e.g. `NSValue<f32>` from being `Eq`
6363
// (even though `[NAN isEqual: NAN]` is true in Objective-C).
64-
impl<$($t: ::core::cmp::Eq $(+ $b)?),*> ::core::cmp::Eq for $name<$($t),*> {}
64+
impl<$($t: ::core::cmp::Eq $(+ $b)? $(+ ?$sized)?),*> ::core::cmp::Eq for $name<$($t),*> {}
6565

6666
// Hashing in Objective-C has the exact same requirement as in Rust:
6767
//
6868
// > If two objects are equal (as determined by the isEqual: method),
6969
// > they must have the same hash value.
7070
//
7171
// See https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418859-hash
72-
impl<$($t: ::core::hash::Hash $(+ $b)?),*> ::core::hash::Hash for $name<$($t),*> {
72+
impl<$($t: ::core::hash::Hash $(+ $b)? $(+ ?$sized)?),*> ::core::hash::Hash for $name<$($t),*> {
7373
#[inline]
7474
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
7575
use $crate::INSObject;
@@ -78,7 +78,7 @@ macro_rules! object {
7878
}
7979

8080
// TODO: Consider T: Debug bound
81-
impl<$($t $(: $b)?),*> ::core::fmt::Debug for $name<$($t),*> {
81+
impl<$($t $(: $b)? $(: ?$sized)?),*> ::core::fmt::Debug for $name<$($t),*> {
8282
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
8383
use ::objc2::MessageReceiver;
8484
use ::alloc::borrow::ToOwned;

objc2-foundation/src/object.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub unsafe trait INSObject: Message {
1515
unsafe { msg_send![self, hash] }
1616
}
1717

18-
fn is_equal<T: INSObject>(&self, other: &T) -> bool {
18+
fn is_equal<T: INSObject + ?Sized>(&self, other: &T) -> bool {
1919
let result: Bool = unsafe { msg_send![self, isEqual: other] };
2020
result.is_true()
2121
}
@@ -40,12 +40,12 @@ object!(unsafe pub struct NSObject<> {
4040

4141
/// ```compile_fail
4242
/// use objc2_foundation::NSObject;
43-
/// fn needs_sync<T: Sync>() {}
43+
/// fn needs_sync<T: Sync + ?Sized>() {}
4444
/// needs_sync::<NSObject>();
4545
/// ```
4646
/// ```compile_fail
4747
/// use objc2_foundation::NSObject;
48-
/// fn needs_send<T: Send>() {}
48+
/// fn needs_send<T: Send + ?Sized>() {}
4949
/// needs_send::<NSObject>();
5050
/// ```
5151
#[cfg(doctest)]

0 commit comments

Comments
 (0)