madsmtm / objc2

Bindings to Apple's frameworks in Rust
https://docs.rs/objc2/
MIT License
290 stars 35 forks source link

Make implementing `ClassType` in `declare_class!` safe #528

Open madsmtm opened 7 months ago

madsmtm commented 7 months ago

Implementing ClassType in declare_class! is unsafe because we need the user to uphold a few safety guarantees, and that was just the most convenient place to put the unsafe keyword.

After https://github.com/madsmtm/objc2/pull/521 though, the only safety guarantees that the user needs to uphold are:

  1. Any invariants that the superclass ClassType::Super may have must be upheld.
  2. ClassType::Mutability must be correct.
  3. Drop must be implemented correctly.

We should work on ways to make fulfilling these unsafe requirements more granular.

One possibility for requirement 2 would be to migrate from an associated type Mutability to a constant, that you must initialize with unsafe if you need certain features:

pub struct Mutability {}

impl Mutability {
    pub const fn interior_mutable() -> Self {
        todo!()
    }

    /// # Safety
    /// ... clearly detailed docs for when this is safe ...
    pub const unsafe fn main_thread_only() -> Self {
        todo!()
    }

    // ...
}

// Usage

declare_class!(
    struct MyClass;

    unsafe impl ClassType for MyClass {
        type Super = NSObject;
        const MUTABILITY: Mutability = Mutability::interior_mutable();
        // Or
        // SAFETY: ...
        // const MUTABILITY: Mutability = unsafe { Mutability::main_thread_only() };
        const NAME: &'static str = "MyClass";
    }

    // ...
);
madsmtm commented 6 months ago

Hmm, just realized that the proposed idea won't work, since you could do const MUTABILITY: Mutability = NSView::MUTABILITY;, and thereby bypass the unsafe.