Skip to content

Commit 19d3df3

Browse files
committed
Refactor how mutability traits are implemented
1 parent f9a0f2b commit 19d3df3

9 files changed

+172
-142
lines changed

crates/objc2/src/mutability.rs

Lines changed: 130 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,39 @@ use core::marker::PhantomData;
3434

3535
use crate::ClassType;
3636

37+
mod private_mutability {
38+
pub trait Sealed {}
39+
}
40+
41+
/// Marker trait for the different types of mutability a class can have.
42+
///
43+
/// This is a sealed trait, and should not need to be implemented. Open an
44+
/// issue if you know a use-case where this restrition should be lifted!
45+
//
46+
// Note: `Sized` is intentionally added to make the trait not object safe.
47+
pub trait Mutability: private_mutability::Sealed + Sized {}
48+
49+
impl private_mutability::Sealed for Root {}
50+
impl Mutability for Root {}
51+
52+
impl private_mutability::Sealed for Immutable {}
53+
impl Mutability for Immutable {}
54+
55+
impl private_mutability::Sealed for Mutable {}
56+
impl Mutability for Mutable {}
57+
58+
impl<MS: ?Sized> private_mutability::Sealed for ImmutableWithMutableSubclass<MS> {}
59+
impl<MS: ?Sized> Mutability for ImmutableWithMutableSubclass<MS> {}
60+
61+
impl<IS: ?Sized> private_mutability::Sealed for MutableWithImmutableSuperclass<IS> {}
62+
impl<IS: ?Sized> Mutability for MutableWithImmutableSuperclass<IS> {}
63+
64+
impl private_mutability::Sealed for InteriorMutable {}
65+
impl Mutability for InteriorMutable {}
66+
67+
impl private_mutability::Sealed for MainThreadOnly {}
68+
impl Mutability for MainThreadOnly {}
69+
3770
/// Helper to make the structs uninhabited, without that being a public fact.
3871
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
3972
enum Never {}
@@ -226,110 +259,6 @@ pub struct MainThreadOnly {
226259
inner: Never,
227260
}
228261

229-
mod private {
230-
use super::*;
231-
232-
pub trait Sealed {}
233-
impl Sealed for Root {}
234-
impl Sealed for Immutable {}
235-
impl Sealed for Mutable {}
236-
impl<MS: ?Sized> Sealed for ImmutableWithMutableSubclass<MS> {}
237-
impl<IS: ?Sized> Sealed for MutableWithImmutableSuperclass<IS> {}
238-
impl Sealed for InteriorMutable {}
239-
impl Sealed for MainThreadOnly {}
240-
241-
pub trait MutabilityIsIdCloneable: Mutability {}
242-
impl MutabilityIsIdCloneable for Root {}
243-
impl MutabilityIsIdCloneable for Immutable {}
244-
impl<MS: ?Sized> MutabilityIsIdCloneable for ImmutableWithMutableSubclass<MS> {}
245-
impl MutabilityIsIdCloneable for InteriorMutable {}
246-
impl MutabilityIsIdCloneable for MainThreadOnly {}
247-
248-
pub trait MutabilityIsRetainable: MutabilityIsIdCloneable {}
249-
impl MutabilityIsRetainable for Immutable {}
250-
impl MutabilityIsRetainable for InteriorMutable {}
251-
impl MutabilityIsRetainable for MainThreadOnly {}
252-
253-
pub trait MutabilityIsAllocableAnyThread: Mutability {}
254-
impl MutabilityIsAllocableAnyThread for Root {}
255-
impl MutabilityIsAllocableAnyThread for Immutable {}
256-
impl MutabilityIsAllocableAnyThread for Mutable {}
257-
impl<MS: ?Sized> MutabilityIsAllocableAnyThread for ImmutableWithMutableSubclass<MS> {}
258-
impl<IS: ?Sized> MutabilityIsAllocableAnyThread for MutableWithImmutableSuperclass<IS> {}
259-
impl MutabilityIsAllocableAnyThread for InteriorMutable {}
260-
261-
pub trait MutabilityIsMutable: Mutability {}
262-
impl MutabilityIsMutable for Mutable {}
263-
impl<IS: ?Sized> MutabilityIsMutable for MutableWithImmutableSuperclass<IS> {}
264-
265-
pub trait MutabilityIsMainThreadOnly: Mutability {}
266-
impl MutabilityIsMainThreadOnly for MainThreadOnly {}
267-
268-
pub trait MutabilityHashIsStable: Mutability {}
269-
impl MutabilityHashIsStable for Immutable {}
270-
impl MutabilityHashIsStable for Mutable {}
271-
impl<MS: ?Sized> MutabilityHashIsStable for ImmutableWithMutableSubclass<MS> {}
272-
impl<IS: ?Sized> MutabilityHashIsStable for MutableWithImmutableSuperclass<IS> {}
273-
274-
pub trait MutabilityCounterpartOrSelf<T: ?Sized>: Mutability {
275-
type Immutable: ?Sized + ClassType;
276-
type Mutable: ?Sized + ClassType;
277-
}
278-
impl<T: ClassType<Mutability = Root>> MutabilityCounterpartOrSelf<T> for Root {
279-
type Immutable = T;
280-
type Mutable = T;
281-
}
282-
impl<T: ClassType<Mutability = Immutable>> MutabilityCounterpartOrSelf<T> for Immutable {
283-
type Immutable = T;
284-
type Mutable = T;
285-
}
286-
impl<T: ClassType<Mutability = Mutable>> MutabilityCounterpartOrSelf<T> for Mutable {
287-
type Immutable = T;
288-
type Mutable = T;
289-
}
290-
impl<T, S> MutabilityCounterpartOrSelf<T> for ImmutableWithMutableSubclass<S>
291-
where
292-
T: ClassType<Mutability = ImmutableWithMutableSubclass<S>>,
293-
S: ClassType<Mutability = MutableWithImmutableSuperclass<T>>,
294-
{
295-
type Immutable = T;
296-
type Mutable = S;
297-
}
298-
impl<T, S> MutabilityCounterpartOrSelf<T> for MutableWithImmutableSuperclass<S>
299-
where
300-
T: ClassType<Mutability = MutableWithImmutableSuperclass<S>>,
301-
S: ClassType<Mutability = ImmutableWithMutableSubclass<T>>,
302-
{
303-
type Immutable = S;
304-
type Mutable = T;
305-
}
306-
impl<T: ClassType<Mutability = InteriorMutable>> MutabilityCounterpartOrSelf<T>
307-
for InteriorMutable
308-
{
309-
type Immutable = T;
310-
type Mutable = T;
311-
}
312-
impl<T: ClassType<Mutability = MainThreadOnly>> MutabilityCounterpartOrSelf<T> for MainThreadOnly {
313-
type Immutable = T;
314-
type Mutable = T;
315-
}
316-
}
317-
318-
/// Marker trait for the different types of mutability a class can have.
319-
///
320-
/// This is a sealed trait, and should not need to be implemented. Open an
321-
/// issue if you know a use-case where this restrition should be lifted!
322-
//
323-
// Note: `Sized` is intentionally added to make the trait not object safe.
324-
pub trait Mutability: private::Sealed + Sized {}
325-
impl Mutability for Root {}
326-
impl Mutability for Immutable {}
327-
impl Mutability for Mutable {}
328-
impl<MS: ?Sized> Mutability for ImmutableWithMutableSubclass<MS> {}
329-
impl<IS: ?Sized> Mutability for MutableWithImmutableSuperclass<IS> {}
330-
impl Mutability for InteriorMutable {}
331-
impl Mutability for MainThreadOnly {}
332-
333262
/// Marker trait for classes where [`Id::clone`] is safe.
334263
///
335264
/// Since the `Foundation` collection types (`NSArray<T>`,
@@ -346,8 +275,15 @@ impl Mutability for MainThreadOnly {}
346275
/// [`Id`]: crate::rc::Id
347276
/// [`Id::clone`]: crate::rc::Id#impl-Clone-for-Id<T>
348277
pub trait IsIdCloneable: ClassType {}
349-
impl<T: ?Sized + ClassType> IsIdCloneable for T where T::Mutability: private::MutabilityIsIdCloneable
350-
{}
278+
279+
trait MutabilityIsIdCloneable: Mutability {}
280+
impl MutabilityIsIdCloneable for Root {}
281+
impl MutabilityIsIdCloneable for Immutable {}
282+
impl<MS: ?Sized> MutabilityIsIdCloneable for ImmutableWithMutableSubclass<MS> {}
283+
impl MutabilityIsIdCloneable for InteriorMutable {}
284+
impl MutabilityIsIdCloneable for MainThreadOnly {}
285+
286+
impl<T: ?Sized + ClassType> IsIdCloneable for T where T::Mutability: MutabilityIsIdCloneable {}
351287

352288
/// Marker trait for classes where the `retain` selector is always safe.
353289
///
@@ -362,7 +298,13 @@ impl<T: ?Sized + ClassType> IsIdCloneable for T where T::Mutability: private::Mu
362298
///
363299
/// [`Id::clone`]: crate::rc::Id#impl-Clone-for-Id<T>
364300
pub trait IsRetainable: IsIdCloneable {}
365-
impl<T: ?Sized + ClassType> IsRetainable for T where T::Mutability: private::MutabilityIsRetainable {}
301+
302+
trait MutabilityIsRetainable: MutabilityIsIdCloneable {}
303+
impl MutabilityIsRetainable for Immutable {}
304+
impl MutabilityIsRetainable for InteriorMutable {}
305+
impl MutabilityIsRetainable for MainThreadOnly {}
306+
307+
impl<T: ?Sized + ClassType> IsRetainable for T where T::Mutability: MutabilityIsRetainable {}
366308

367309
/// Marker trait for classes that can be allocated from any thread.
368310
///
@@ -374,8 +316,17 @@ impl<T: ?Sized + ClassType> IsRetainable for T where T::Mutability: private::Mut
374316
/// - [`MutableWithImmutableSuperclass`].
375317
/// - [`InteriorMutable`].
376318
pub trait IsAllocableAnyThread: ClassType {}
319+
320+
trait MutabilityIsAllocableAnyThread: Mutability {}
321+
impl MutabilityIsAllocableAnyThread for Root {}
322+
impl MutabilityIsAllocableAnyThread for Immutable {}
323+
impl MutabilityIsAllocableAnyThread for Mutable {}
324+
impl<MS: ?Sized> MutabilityIsAllocableAnyThread for ImmutableWithMutableSubclass<MS> {}
325+
impl<IS: ?Sized> MutabilityIsAllocableAnyThread for MutableWithImmutableSuperclass<IS> {}
326+
impl MutabilityIsAllocableAnyThread for InteriorMutable {}
327+
377328
impl<T: ?Sized + ClassType> IsAllocableAnyThread for T where
378-
T::Mutability: private::MutabilityIsAllocableAnyThread
329+
T::Mutability: MutabilityIsAllocableAnyThread
379330
{
380331
}
381332

@@ -389,7 +340,12 @@ impl<T: ?Sized + ClassType> IsAllocableAnyThread for T where
389340
/// technically mutable), since it is allowed to mutate through shared
390341
/// references.
391342
pub trait IsMutable: ClassType {}
392-
impl<T: ?Sized + ClassType> IsMutable for T where T::Mutability: private::MutabilityIsMutable {}
343+
344+
trait MutabilityIsMutable: Mutability {}
345+
impl MutabilityIsMutable for Mutable {}
346+
impl<IS: ?Sized> MutabilityIsMutable for MutableWithImmutableSuperclass<IS> {}
347+
348+
impl<T: ?Sized + ClassType> IsMutable for T where T::Mutability: MutabilityIsMutable {}
393349

394350
/// Marker trait for classes that are only available on the main thread.
395351
///
@@ -402,10 +358,11 @@ impl<T: ?Sized + ClassType> IsMutable for T where T::Mutability: private::Mutabi
402358
//
403359
// Note: MainThreadMarker::from relies on this.
404360
pub trait IsMainThreadOnly: ClassType {}
405-
impl<T: ?Sized + ClassType> IsMainThreadOnly for T where
406-
T::Mutability: private::MutabilityIsMainThreadOnly
407-
{
408-
}
361+
362+
trait MutabilityIsMainThreadOnly: Mutability {}
363+
impl MutabilityIsMainThreadOnly for MainThreadOnly {}
364+
365+
impl<T: ?Sized + ClassType> IsMainThreadOnly for T where T::Mutability: MutabilityIsMainThreadOnly {}
409366

410367
/// Marker trait for classes whose `hash` and `isEqual:` methods are stable.
411368
///
@@ -425,7 +382,14 @@ impl<T: ?Sized + ClassType> IsMainThreadOnly for T where
425382
//
426383
// TODO: Exclude generic types like `NSArray<NSView>` from this!
427384
pub trait HasStableHash: ClassType {}
428-
impl<T: ?Sized + ClassType> HasStableHash for T where T::Mutability: private::MutabilityHashIsStable {}
385+
386+
trait MutabilityHashIsStable: Mutability {}
387+
impl MutabilityHashIsStable for Immutable {}
388+
impl MutabilityHashIsStable for Mutable {}
389+
impl<MS: ?Sized> MutabilityHashIsStable for ImmutableWithMutableSubclass<MS> {}
390+
impl<IS: ?Sized> MutabilityHashIsStable for MutableWithImmutableSuperclass<IS> {}
391+
392+
impl<T: ?Sized + ClassType> HasStableHash for T where T::Mutability: MutabilityHashIsStable {}
429393

430394
/// Retrieve the immutable/mutable counterpart class, and fall back to `Self`
431395
/// if not applicable.
@@ -449,12 +413,61 @@ pub trait CounterpartOrSelf: ClassType {
449413
/// `NSMutableString` has itself (`NSMutableString`).
450414
type Mutable: ?Sized + ClassType;
451415
}
416+
417+
mod private_counterpart {
418+
use super::*;
419+
420+
pub trait MutabilityCounterpartOrSelf<T: ?Sized>: Mutability {
421+
type Immutable: ?Sized + ClassType;
422+
type Mutable: ?Sized + ClassType;
423+
}
424+
impl<T: ClassType<Mutability = Root>> MutabilityCounterpartOrSelf<T> for Root {
425+
type Immutable = T;
426+
type Mutable = T;
427+
}
428+
impl<T: ClassType<Mutability = Immutable>> MutabilityCounterpartOrSelf<T> for Immutable {
429+
type Immutable = T;
430+
type Mutable = T;
431+
}
432+
impl<T: ClassType<Mutability = Mutable>> MutabilityCounterpartOrSelf<T> for Mutable {
433+
type Immutable = T;
434+
type Mutable = T;
435+
}
436+
impl<T, MS> MutabilityCounterpartOrSelf<T> for ImmutableWithMutableSubclass<MS>
437+
where
438+
T: ClassType<Mutability = ImmutableWithMutableSubclass<MS>>,
439+
MS: ClassType<Mutability = MutableWithImmutableSuperclass<T>>,
440+
{
441+
type Immutable = T;
442+
type Mutable = MS;
443+
}
444+
impl<T, IS> MutabilityCounterpartOrSelf<T> for MutableWithImmutableSuperclass<IS>
445+
where
446+
T: ClassType<Mutability = MutableWithImmutableSuperclass<IS>>,
447+
IS: ClassType<Mutability = ImmutableWithMutableSubclass<T>>,
448+
{
449+
type Immutable = IS;
450+
type Mutable = T;
451+
}
452+
impl<T: ClassType<Mutability = InteriorMutable>> MutabilityCounterpartOrSelf<T>
453+
for InteriorMutable
454+
{
455+
type Immutable = T;
456+
type Mutable = T;
457+
}
458+
impl<T: ClassType<Mutability = MainThreadOnly>> MutabilityCounterpartOrSelf<T> for MainThreadOnly {
459+
type Immutable = T;
460+
type Mutable = T;
461+
}
462+
}
463+
452464
impl<T: ?Sized + ClassType> CounterpartOrSelf for T
453465
where
454-
T::Mutability: private::MutabilityCounterpartOrSelf<T>,
466+
T::Mutability: private_counterpart::MutabilityCounterpartOrSelf<T>,
455467
{
456-
type Immutable = <T::Mutability as private::MutabilityCounterpartOrSelf<T>>::Immutable;
457-
type Mutable = <T::Mutability as private::MutabilityCounterpartOrSelf<T>>::Mutable;
468+
type Immutable =
469+
<T::Mutability as private_counterpart::MutabilityCounterpartOrSelf<T>>::Immutable;
470+
type Mutable = <T::Mutability as private_counterpart::MutabilityCounterpartOrSelf<T>>::Mutable;
458471
}
459472

460473
#[cfg(test)]

crates/test-ui/ui/declare_class_mut_self_not_mutable.stderr

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0277]: the trait bound `InteriorMutable: mutability::private::MutabilityIsMutable` is not satisfied
1+
error[E0277]: the trait bound `InteriorMutable: mutability::MutabilityIsMutable` is not satisfied
22
--> ui/declare_class_mut_self_not_mutable.rs
33
|
44
| / declare_class!(
@@ -10,10 +10,10 @@ error[E0277]: the trait bound `InteriorMutable: mutability::private::MutabilityI
1010
| | );
1111
| | ^
1212
| | |
13-
| |_the trait `mutability::private::MutabilityIsMutable` is not implemented for `InteriorMutable`
13+
| |_the trait `mutability::MutabilityIsMutable` is not implemented for `InteriorMutable`
1414
| required by a bound introduced by this call
1515
|
16-
= help: the following other types implement trait `mutability::private::MutabilityIsMutable`:
16+
= help: the following other types implement trait `mutability::MutabilityIsMutable`:
1717
Mutable
1818
MutableWithImmutableSuperclass<IS>
1919
= note: required for `CustomObject` to implement `IsMutable`
@@ -28,7 +28,7 @@ note: required by a bound in `ClassBuilder::add_method`
2828
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ClassBuilder::add_method`
2929
= note: this error originates in the macro `$crate::__declare_class_register_out` which comes from the expansion of the macro `declare_class` (in Nightly builds, run with -Z macro-backtrace for more info)
3030

31-
error[E0277]: the trait bound `InteriorMutable: mutability::private::MutabilityIsMutable` is not satisfied
31+
error[E0277]: the trait bound `InteriorMutable: mutability::MutabilityIsMutable` is not satisfied
3232
--> ui/declare_class_mut_self_not_mutable.rs
3333
|
3434
| / declare_class!(
@@ -40,10 +40,10 @@ error[E0277]: the trait bound `InteriorMutable: mutability::private::MutabilityI
4040
| | );
4141
| | ^
4242
| | |
43-
| |_the trait `mutability::private::MutabilityIsMutable` is not implemented for `InteriorMutable`
43+
| |_the trait `mutability::MutabilityIsMutable` is not implemented for `InteriorMutable`
4444
| required by a bound introduced by this call
4545
|
46-
= help: the following other types implement trait `mutability::private::MutabilityIsMutable`:
46+
= help: the following other types implement trait `mutability::MutabilityIsMutable`:
4747
Mutable
4848
MutableWithImmutableSuperclass<IS>
4949
= note: required for `CustomObject` to implement `IsMutable`
@@ -58,7 +58,7 @@ note: required by a bound in `ClassBuilder::add_method`
5858
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ClassBuilder::add_method`
5959
= note: this error originates in the macro `$crate::__declare_class_register_out` which comes from the expansion of the macro `declare_class` (in Nightly builds, run with -Z macro-backtrace for more info)
6060

61-
error[E0277]: the trait bound `InteriorMutable: mutability::private::MutabilityIsMutable` is not satisfied
61+
error[E0277]: the trait bound `InteriorMutable: mutability::MutabilityIsMutable` is not satisfied
6262
--> ui/declare_class_mut_self_not_mutable.rs
6363
|
6464
| / declare_class!(
@@ -70,10 +70,10 @@ error[E0277]: the trait bound `InteriorMutable: mutability::private::MutabilityI
7070
| | );
7171
| | ^
7272
| | |
73-
| |_the trait `mutability::private::MutabilityIsMutable` is not implemented for `InteriorMutable`
73+
| |_the trait `mutability::MutabilityIsMutable` is not implemented for `InteriorMutable`
7474
| required by a bound introduced by this call
7575
|
76-
= help: the following other types implement trait `mutability::private::MutabilityIsMutable`:
76+
= help: the following other types implement trait `mutability::MutabilityIsMutable`:
7777
Mutable
7878
MutableWithImmutableSuperclass<IS>
7979
= note: required for `CustomObject` to implement `IsMutable`

crates/test-ui/ui/main_thread_only_not_allocable.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0277]: the trait bound `MainThreadOnly: mutability::private::MutabilityIsAllocableAnyThread` is not satisfied
1+
error[E0277]: the trait bound `MainThreadOnly: mutability::MutabilityIsAllocableAnyThread` is not satisfied
22
--> ui/main_thread_only_not_allocable.rs
33
|
44
| let _ = MyMainThreadOnlyClass::alloc();
5-
| ^^^^^^^^^^^^^^^^^^^^^ the trait `mutability::private::MutabilityIsAllocableAnyThread` is not implemented for `MainThreadOnly`
5+
| ^^^^^^^^^^^^^^^^^^^^^ the trait `mutability::MutabilityIsAllocableAnyThread` is not implemented for `MainThreadOnly`
66
|
7-
= help: the following other types implement trait `mutability::private::MutabilityIsAllocableAnyThread`:
7+
= help: the following other types implement trait `mutability::MutabilityIsAllocableAnyThread`:
88
Root
99
Immutable
1010
Mutable
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use icrate::Foundation::{MainThreadMarker, NSObject};
2+
3+
fn main() {
4+
let obj = NSObject::new();
5+
let mtm = MainThreadMarker::from(&*obj);
6+
}

0 commit comments

Comments
 (0)