Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift Vec<primitive> Return Type and Function Argument #229

Merged
merged 10 commits into from
Jun 20, 2023

Conversation

timwedde
Copy link
Contributor

Fixes #228.

This enables the following use case:

// Rust
fn main() {
    let bytes = ffi::receive_bytes();
    println!("bytes: {:?}", bytes);

    let vec: Vec<u8> = vec![6, 1, 2, 3, 4, 5];
    ffi::send_bytes(vec);
}

#[swift_bridge::bridge]
mod ffi {
    extern "Swift" {
        fn receive_bytes() -> Vec<u8>;
        fn send_bytes(vec: Vec<u8>);
    }
}
// Swift
func send_bytes(vec: RustVec<UInt8>) {
    print("Received \(vec.len()) bytes from Rust")
    for val in vec {
        print(val)
    }
}

func receive_bytes() -> RustVec<UInt8> {
    let vec = RustVec<UInt8>()
    for i in 0 ... 4 {
        vec.push(value: UInt8(i))
    }
    return vec
}

This is chiefly intended for easy bidirectional byte exchanges but should work for all primitive types, at least the ones I tested with.

The codegen tests pass but I was unable to get the integration tests to run: They also fail for me on master and I don't understand enough of how they work to properly debug them. The (very long) error messages ends with this, which seems to be the culprit:

field has incomplete type 'struct swift_bridge$tuple$I32ResultTestOpaqueRustTypeString'

I attempted to add some integration tests for both directions anyway, but given that I'm operating 'blind' on that part I can't assure you whether these work or not.

I'm rather certain that there's still issues with my PR given that this is my first time dealing with this kind of interop work, so by all means do let me know how to address the current weaknesses/problems and I'll do my best to resolve them.

timwedde added 3 commits June 14, 2023 23:15
This exchanges raw pointers when:
- send a Vec from Rust to Swift
- receiving a Vec from Swift to Rust

In all other cases the behavior is the same as before.
This adds test for both the argument and the return value variant.
Can't actually get these to run: The integration tests seem to already by broken. They fail with something to the tune of
> field has incomplete type 'struct __swift_bridge__$tuple$I32ResultTestOpaqueRustTypeString'
@NiwakaDev
Copy link
Collaborator

NiwakaDev commented Jun 14, 2023

@timwedde

field has incomplete type 'struct swift_bridge$tuple$I32ResultTestOpaqueRustTypeString'

This error is not due to this PR. If you want to know more detail, please see #225.

It seems like this PR is fine. Thanks!!

Copy link
Owner

@chinedufn chinedufn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the very detailed PR body.

This looks great to me. Left some very minor feedback then after that this is good to go.

Comment on lines 1 to 6
//
// String.swift
// SwiftRustIntegrationTestRunner
//
// Created by Frankie Nwafili on 2/18/22.
//
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can delete this comment. Xcode typically auto generates them but we don't really need them

}

fn expected_c_header() -> ExpectedCHeader {
ExpectedCHeader::ContainsAfterTrim("")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will pass for all strings string all strings contain "".

You can use ExpectedCHeader::ExactAfterTrim("") here instead.


import Foundation

func send_bytes(vec _: RustVec<UInt8>) {}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets call these swift_arg_vec_u8 and swift_return_vec_u8.

This way we can more easily distinguish these from other FFI functions.


import Foundation

func send_bytes(vec _: RustVec<UInt8>) {}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this function assert that the bytes are 1, 2, 3, 4, 5

}
}

fn run_vec_tests() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

}

fn expected_c_header() -> ExpectedCHeader {
ExpectedCHeader::ContainsAfterTrim("")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

::ExactAfterTrim

@@ -25,6 +25,28 @@ mod ffi {
arg: Vec<TransparentEnumInsideVecT>,
) -> Vec<TransparentEnumInsideVecT>;
}

extern "Rust" {
fn run_vec_tests();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to call this on the Swift side in VecTests.rs

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/chinedufn/swift-bridge/blob/master/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/VecTests.swift#L11

something like:

/// Verify that Rust can pass `RustVec`s to and receive `RustVec`s from Swift.
func testRustCallsSwiftRustVecFunctions() {
    run_vec_tests()
}

} else {
"UnsafeMutableRawPointer".to_string()
}
},
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timwedde
Copy link
Contributor Author

Alright, I think I addressed all of the comments, let me know how I did 👍

@chinedufn
Copy link
Owner

Thanks!

@chinedufn
Copy link
Owner

A UI test is failing but I believe it's fixed in #230 so I'll merge this

@chinedufn chinedufn merged commit ffe20d8 into chinedufn:master Jun 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

How to return Vec<u8> from Swift to Rust
3 participants