chinedufn / swift-bridge

swift-bridge facilitates Rust and Swift interop.
https://chinedufn.github.io/swift-bridge
Apache License 2.0
801 stars 57 forks source link

Binding more complicated swift classes to use in rust #116

Open ericmarkmartin opened 1 year ago

ericmarkmartin commented 1 year ago

I appreciate the example showing how to link swift into rust, but I think the examples are all pretty simple swift. I'm trying to use this library to write bindings for an Apple framework, so the swift classes involved a bit more complex.

For instance if I have nested swift structs/classes like

class Foo {
  var x : Int

  init(x : Int) {
    self.x = x
  }

  struct Bar {
    var y: Int
  }

  func baz(bar: Bar) -> Int {
    return x + bar.y
  }
}

and I want to do something like

let foo = Foo(x: 1)
let bar = Foo.Bar(y: 2)
print("baz: \(foo.baz(bar: bar))")

but from rust, how would I write the bindings?

Also, some swift libraries have vars that I might want to access from rust. Is it possible to write bindings to do this?

chinedufn commented 1 year ago

Also, some swift libraries have vars that I might want to access from rust. Is it possible to write bindings to do this?

Right now we have a #[swift_bridge(get)] attribute that can be used to return a Rust struct field.

https://github.com/chinedufn/swift-bridge/blob/master/book/src/bridge-module/functions/README.md?plain=1#L130-L157

We could make it possible to do the same thing on Swift classes.

#[swift_bridge::bridge]
mod ffi {
     extern "Swift" {
        type Foo;

        // Returns `Foo.x`
        #[swift_bridge(get(x))
        fn x(&self) -> UInt;
    }
}

Would this work for your use case?


As for exposing nested types.. Hmm.. what about something along the lines of:

#[swift_bridge::bridge]
mod ffi {
    extern "Swift" {
        type Foo;
        fn baz(&self, bar: Bar) -> isize;
    }

    extern "Swift" {
        #[swift_bridge(type_path = "Foo.Bar")]
        type Bar;

        #[swift_bridge(init)]
        fn new(y: isize) -> Bar;
    }
}

Would this work for your use case? Specifically, are there more complex nesting use cases that the above approach wouldn't account for?


Yeah my main use case has been Swift calling Rust, so the features and examples are currently very biased towards that.

We totally want to also have good support for Rust calling Swift, so I'd love to start writing some more Swifty examples (with some help from experienced Swift devs since I don't know the language well).

If you have any other use cases in mind please feel free to share them. I can in turn split out some separate issues for some of the above solutions (unless you think that they won't solve the problem) and we can get them implemented and documented.


Thanks for opening this issue. Sorry for the delay!