madsmtm / objc2

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

Swift array count: expected return to have type code 'q', but found 'Q' #566

Open 1tgr opened 3 months ago

1tgr commented 3 months ago

I'm exposing this Rust function to Swift:

#[no_mangle]
pub extern "C" fn time_series_eval(
    exprs: *mut NSArray<NSString>,
    error: &mut *mut NSError,
) -> *mut NSDictionary<NSString, NSArray> {
    let exprs = exprs.as_ref().unwrap().iter();
    // do something with exprs
}

I call it like this from the Swift side:

var error: NSError?
let result = time_series_eval(["abc"], &error)

But the Rust panics:

~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/icrate-0.1.0/src/generated/Foundation/NSEnumerator.rs:6:1:
invalid message send to -[Swift.__SwiftDeferredNSArray countByEnumeratingWithState:objects:count:]: expected return to have type code 'q', but found 'Q'

I think this is telling me that Swift arrays and objc2's arrays don't agree on signed vs unsigned?

madsmtm commented 3 months ago

I think this is telling me that Swift arrays and objc2's arrays don't agree on signed vs unsigned?

Rather, Swift is lazy and uses Int instead of the more correct type UInt here; the difference doesn't really matter to them, as arrays likely won't be able to ever get so large that it matters.

I've opened https://github.com/madsmtm/objc2/pull/567 to fix this, although I'm a bit unsure what the right approach is. In the meantime the easiest fix for you is probably to do one of:

1tgr commented 3 months ago

Thanks for the quick response. I took a local copy of the repo and did a quick hack equivalent to #567 that avoided the problem and I'll try taking a Git dependency on #567 for now.