Open chinedufn opened 2 years ago
Would there be a possibility that we generate an overarching struct in swift, something like
struct MyStruct<A, B> {
// ...
}
That uses the correct struct for each type of A
and B
.
Just a thought, not sure how realistic/practical this is or how we would implement it.
Might also just be something to keep in mind for later.
Hmm interesting.
So that would look something like:
struct MyStruct<A, B> {
field1: A,
field2: B,
}
#[swift_bridge::bridge]
mod ffi {
extern "Rust" {
#[swift_bridge(declare_generic)]
type MyStruct<A, B>;
}
extern "Rust" {
type MyStruct<u32, String>;
#[swift_bridge(associated_to = MyStruct<u32, String>)]
fn new() -> MyStruct<u32, String>;
}
}
// Swift
let myStruct: MyStruct<u32, String> = MyStruct.new();
Where the generated Swift code looked something like:
// This comes from the `#[swift_bridge(declare_generic)]`
class MyStruct<A, B> {
// ...
}
extension MyStruct where A == UInt32, B == RustString {
class func new() -> MyStruct<UInt32, RustString> {
return __swift_bridge__$MyStruct$u32_RustString$new()
}
}
Definitely seems do-able, and seems a bit more ergonomic. I like the idea.
@cozyGalvinism I'm curious about your thoughts on how to best support generics.
Did you find that using type aliases felt better, or would you have preferred to be able to do something like what's been outlined in this issue?
I'm trying to get a good sense of whether or not we should even implement generics support or if we should just stick to type aliases as the recommended way for handling generics.
I'd like to avoid introducing extra complexity unless there's a clear reason to do so.
@Jomy10 if you have any thoughts on this feel free to share as well
Where the generated Swift code looked something like:
// This comes from the `#[swift_bridge(declare_generic)]` class MyStruct<A, B> { // ... } extension MyStruct where A == UInt32, B == RustString { class func new() -> MyStruct<UInt32, RustString> { return __swift_bridge__$MyStruct$u32_RustString$new() } }
That looks right to me.
Instead of #[declare(generic)]
I think we'd just fill in the generics.
#[swift_bridge::bridge]
mod ffi {
extern "Rust" {
type MyStruct<u32, String>;
}
}
This way there isn't a separate way of declaring opaque types.
Also, this approach lets us generate the freeing function that gets called whenever the class MyStruct<UInt32, RustString>
instance is dropped on the Swift side.
If anyone is reading this and needs support for generics please let me know. I'm waiting until someone needs generics before implementing a first version of support.
(I'm not too familiar with the terms opaque/transparent types) but I think my use case is related to this issue.
How would you use a struct defined outside the swift bridge macro? Ideally I would love that I could do this:
use librespot::metadata::Track;
#[swift_bridge::bridge]
mod ffi {
extern "Rust" {
type RustApp;
fn get_track(self: &RustApp, track_id: &str) -> Option<Track>;
}
}
or
use librespot::{
metadata::{Track, FileFormat},
core::{spotify_id::{SpotifyId, FileId, SpotifyAudioType}}
};
#[swift_bridge::bridge]
mod ffi {
extern "Rust" {
type RustApp;
type Track;
type FileFormat;
type SpotifyId;
type FileId;
type SpotifyAudioType;
fn get_track(self: &RustApp, track_id: &str) -> Option<Track>;
}
}
As I understand, currently I would need to re-define the structs in the ffi
module - right? And since the Track
struct contains many other structs, I would need to redefine them also, right?
https://docs.rs/librespot-metadata/0.3.1/librespot_metadata/struct.Track.html
Hey Ben. This actually isn't related to generics.
Feel free to open a new issue with your questions (as well as some context around what you're trying to be able to do) and I'll be more than happy to help you figure out exactly how to do whatever you are trying to do.
https://github.com/chinedufn/swift-bridge/pull/81 adds support for generic Rust types.
So far you can pass them around in function arg/returns but you can't call methods on generic Rust types just yet.
More generics support https://github.com/chinedufn/swift-bridge/pull/84
All that's remaining to close this issue is supporting self
&self
and &mut self
methods on generic Rust types.
Something like:
Note that generics are possible today using type aliases: