Brendonovich / swift-rs

Call Swift functions from Rust with ease!
Apache License 2.0
253 stars 30 forks source link

Handle nil #4

Closed 0rvar closed 2 years ago

0rvar commented 2 years ago

How do I handle nil returned from a swift function? The *const pointer in SRObject is private, so I can't check result.0.is_null(). Any other option?

EDIT: Opened a PR: #5

Brendonovich commented 2 years ago

I never considered that Swift allowed nil values 😅 Adding a null check is one way to handle it, but I think it'd be better to allow using Rust's Option type. I've done some testing and it seems that thanks to null-pointer optimisation, this can be done quite easily! Just gotta make SRObject contain a NonNull pointer and use #[repr(transparent)] rather than #[repr(C)]. Works with SRObject and SRArray.

0rvar commented 2 years ago

@Brendonovich I am not quite sure what you mean.

In my case, the swift function is defined kind of like this:

@_cdecl("get_foo")
public func getFoo() -> Foo? {}

So, the returned object itself is nullable. How would I then type the linked function in Rust?

I tried this:

#[link(name = "myfoolib")]
extern "C" {
    fn get_foo() -> SRObject<Option<FooObjc>>;
}

But this causes a segfault when I dereference the SRObject and nil was returned from swift

0rvar commented 2 years ago

I managed to get this working, but only once I created this type manually:

#[repr(C)]
#[derive(Debug)]
enum NullablePtr<T> {
    Null,
    NonNull(T),
}

Then I could define the linked function like this:

#[link(name = "myfoolib")]
extern "C" {
    fn get_foo() -> NullablePtr<SRObject<FooObjc>>;
}
Brendonovich commented 2 years ago

@0rvar The solution I outlined was to do with the internals of SRObject, in your case all that would be required is giving get_foo the signature () -> Option<SRObject<FooObjc>>. The NonNull pointer will be held internally by SRObject, and will allow Rust to ensure that the Option works properly. I haven't pushed any changes yet but will soon so that you can try it out

0rvar commented 2 years ago

Option<SRObject<T>> works perfectly with latest master! Thank you