-
Notifications
You must be signed in to change notification settings - Fork 54
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
Vec of shared struct #91
Comments
Hey. Yup you're right that Right now we only support swift-bridge/crates/swift-bridge-ir/src/codegen/codegen_tests/vec_codegen_tests.rs Lines 226 to 236 in 4d0a18f
swift-bridge/crates/swift-integration-tests/src/vec.rs Lines 1 to 17 in b26dcf9
swift-bridge/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/VecTests.swift Lines 72 to 81 in b26dcf9
Normally I'd try to get this to you right away but I'm pushing up against a deadline right now. I can implement support for this over the weekend if that works for you? Otherwise if it's urgent I'd be happy to provide guidance on how to implement this. Thanks for opening this issue! |
Yes that’d be great! Thank you! |
I'm in need of this too, would be awesome to get added! |
@chinedufn this is blocking me currently so I'd be happy to try and implement, do you have any pointers as to how to do so? |
Hey! Thanks for the heads up. I'll write up some detailed instructions either tonight or tomorrow. |
Hey. Sorry I'll have to get to this today or tomorrow! Will definitely write these for you just need to finish a couple more unrelated things. Thanks! |
Thanks for waiting! I've written up a guide to adding support for Implementing Support for
|
class VecTests: XCTestCase { |
swift-bridge/crates/swift-bridge-ir/src/codegen/codegen_tests/vec_codegen_tests.rs
Lines 7 to 20 in c1fd717
/// Verify that we emit Rust, Swift and C header code that allows an extern "Rust" type be used | |
/// within a Vec<T>. | |
mod extern_rust_type_vec_support { | |
use super::*; | |
fn bridge_module_tokens() -> TokenStream { | |
quote! { | |
mod ffi { | |
extern "Rust" { | |
type MyRustType; | |
} | |
} | |
} | |
} |
Integration Tests
Add an integration test for Vec<TransparentStruct>
.
You can use Vec<TransparentEnum>
as a guide:
swift-bridge/SwiftRustIntegrationTestRunner/SwiftRustIntegrationTestRunnerTests/VecTests.swift
Lines 84 to 94 in c1fd717
/// Verify that a Vec<T> of transparent enums can be used as an argument and return /// type for extern "Rust" functions. func testReflectVecOfTransparentEnum() throws { let vec: RustVec<TransparentEnumInsideVecT> = RustVec() vec.push(value: TransparentEnumInsideVecT.VariantB) let reflected = rust_reflect_vec_transparent_enum(vec) XCTAssertEqual(reflected.len(), 1) XCTAssertEqual(reflected.get(index: 0)!, TransparentEnumInsideVecT.VariantB) XCTAssertEqual(reflected.pop()!, TransparentEnumInsideVecT.VariantB) } swift-bridge/crates/swift-integration-tests/src/vec.rs
Lines 23 to 27 in c1fd717
extern "Rust" { fn rust_reflect_vec_transparent_enum( arg: Vec<TransparentEnumInsideVecT>, ) -> Vec<TransparentEnumInsideVecT>; }
Codegen Tests
Add codegen tests, similar to the ones for transparent enums
swift-bridge/crates/swift-bridge-ir/src/codegen/codegen_tests/vec_codegen_tests.rs
Lines 282 to 423 in c1fd717
/// Verify that we emit Rust, Swift and C header code that allows a transparent enum be used /// within a Vec<T>. mod transparent_enum_vec_support { use super::*; fn bridge_module_tokens() -> TokenStream { quote! { mod ffi { enum SomeEnum { VariantA, VariantB } } } } fn expected_rust_tokens() -> ExpectedRustTokens { ExpectedRustTokens::Contains(quote! { const _: () = { #[doc(hidden)] #[export_name = "__swift_bridge__$Vec_SomeEnum$new"] pub extern "C" fn _new() -> *mut Vec<SomeEnum> { Box::into_raw(Box::new(Vec::new())) } #[doc(hidden)] #[export_name = "__swift_bridge__$Vec_SomeEnum$drop"] pub extern "C" fn _drop(vec: *mut Vec<SomeEnum>) { let vec = unsafe { Box::from_raw(vec) }; drop(vec) } #[doc(hidden)] #[export_name = "__swift_bridge__$Vec_SomeEnum$len"] pub extern "C" fn _len(vec: *const Vec<SomeEnum>) -> usize { unsafe { &*vec }.len() } #[doc(hidden)] #[export_name = "__swift_bridge__$Vec_SomeEnum$get"] pub extern "C" fn _get(vec: *const Vec<SomeEnum>, index: usize) -> __swift_bridge__Option_SomeEnum { let vec = unsafe { &*vec }; let val = vec.get(index).map(|v| *v); __swift_bridge__Option_SomeEnum::from_rust_repr(val) } #[doc(hidden)] #[export_name = "__swift_bridge__$Vec_SomeEnum$get_mut"] pub extern "C" fn _get_mut(vec: *mut Vec<SomeEnum>, index: usize) -> __swift_bridge__Option_SomeEnum { let vec = unsafe { &mut *vec }; let val = vec.get_mut(index).map(|v| *v); __swift_bridge__Option_SomeEnum::from_rust_repr(val) } #[doc(hidden)] #[export_name = "__swift_bridge__$Vec_SomeEnum$push"] pub extern "C" fn _push(vec: *mut Vec<SomeEnum>, val: __swift_bridge__SomeEnum) { unsafe { &mut *vec }.push(val.into_rust_repr()) } #[doc(hidden)] #[export_name = "__swift_bridge__$Vec_SomeEnum$pop"] pub extern "C" fn _pop(vec: *mut Vec<SomeEnum>) -> __swift_bridge__Option_SomeEnum { let vec = unsafe { &mut *vec }; let val = vec.pop(); __swift_bridge__Option_SomeEnum::from_rust_repr(val) } #[doc(hidden)] #[export_name = "__swift_bridge__$Vec_SomeEnum$as_ptr"] pub extern "C" fn _as_ptr(vec: *const Vec<SomeEnum>) -> *const SomeEnum { unsafe { & *vec }.as_ptr() } }; }) } fn expected_swift_code() -> ExpectedSwiftCode { ExpectedSwiftCode::ContainsAfterTrim( r#" extension SomeEnum: Vectorizable { public static func vecOfSelfNew() -> UnsafeMutableRawPointer { __swift_bridge__$Vec_SomeEnum$new() } public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) { __swift_bridge__$Vec_SomeEnum$drop(vecPtr) } public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) { __swift_bridge__$Vec_SomeEnum$push(vecPtr, value.intoFfiRepr()) } public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional<Self> { let maybeEnum = __swift_bridge__$Vec_SomeEnum$pop(vecPtr) return maybeEnum.intoSwiftRepr() } public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional<Self> { let maybeEnum = __swift_bridge__$Vec_SomeEnum$get(vecPtr, index) return maybeEnum.intoSwiftRepr() } public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional<Self> { let maybeEnum = __swift_bridge__$Vec_SomeEnum$get_mut(vecPtr, index) return maybeEnum.intoSwiftRepr() } public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt { __swift_bridge__$Vec_SomeEnum$len(vecPtr) } } "#, ) } fn expected_c_header() -> ExpectedCHeader { ExpectedCHeader::ContainsAfterTrim( r#" void* __swift_bridge__$Vec_SomeEnum$new(void); void __swift_bridge__$Vec_SomeEnum$drop(void* vec_ptr); void __swift_bridge__$Vec_SomeEnum$push(void* vec_ptr, __swift_bridge__$SomeEnum item); __swift_bridge__$Option$SomeEnum __swift_bridge__$Vec_SomeEnum$pop(void* vec_ptr); __swift_bridge__$Option$SomeEnum __swift_bridge__$Vec_SomeEnum$get(void* vec_ptr, uintptr_t index); __swift_bridge__$Option$SomeEnum __swift_bridge__$Vec_SomeEnum$get_mut(void* vec_ptr, uintptr_t index); uintptr_t __swift_bridge__$Vec_SomeEnum$len(void* vec_ptr); void* __swift_bridge__$Vec_SomeEnum$as_ptr(void* vec_ptr); "#, ) } #[test] fn transparent_enum_vec_support() { CodegenTest { bridge_module: bridge_module_tokens().into(), expected_rust_tokens: expected_rust_tokens(), expected_swift_code: expected_swift_code(), expected_c_header: expected_c_header(), } .test(); } } swift-bridge/crates/swift-bridge-ir/src/codegen/codegen_tests/vec_codegen_tests.rs
Lines 425 to 479 in c1fd717
/// Test code generation for Rust function that returns a Vec<T> where T is a transparent enum. mod extern_rust_fn_return_vec_of_transparent_enum { use super::*; fn bridge_module_tokens() -> TokenStream { quote! { mod ffi { enum SomeEnum { A } extern "Rust" { fn some_function() -> Vec<SomeEnum>; } } } } fn expected_rust_tokens() -> ExpectedRustTokens { ExpectedRustTokens::Contains(quote! { pub extern "C" fn __swift_bridge__some_function() -> *mut Vec<SomeEnum> { Box::into_raw(Box::new(super::some_function())) } }) } fn expected_swift_code() -> ExpectedSwiftCode { ExpectedSwiftCode::ContainsAfterTrim( r#" func some_function() -> RustVec<SomeEnum> { RustVec(ptr: __swift_bridge__$some_function()) } "#, ) } fn expected_c_header() -> ExpectedCHeader { ExpectedCHeader::ContainsAfterTrim( r#" void* __swift_bridge__$some_function(void); "#, ) } #[test] fn extern_rust_fn_return_vec_of_transparent_enum() { CodegenTest { bridge_module: bridge_module_tokens().into(), expected_rust_tokens: expected_rust_tokens(), expected_swift_code: expected_swift_code(), expected_c_header: expected_c_header(), } .test(); } } swift-bridge/crates/swift-bridge-ir/src/codegen/codegen_tests/vec_codegen_tests.rs
Lines 481 to 538 in c1fd717
/// Test code generation for Rust function that has an argument /// Vec<T> where T is a transparent enum. mod extern_rust_fn_arg_vec_of_transparent_enum { use super::*; fn bridge_module_tokens() -> TokenStream { quote! { mod ffi { enum SomeEnum { A } extern "Rust" { type MyRustType; fn some_function(arg: Vec<SomeEnum>); } } } } fn expected_rust_tokens() -> ExpectedRustTokens { ExpectedRustTokens::Contains(quote! { pub extern "C" fn __swift_bridge__some_function( arg: *mut Vec<SomeEnum> ) { super::some_function(unsafe { * Box::from_raw(arg) }) } }) } fn expected_swift_code() -> ExpectedSwiftCode { ExpectedSwiftCode::ContainsAfterTrim( r#" func some_function(_ arg: RustVec<SomeEnum>) { __swift_bridge__$some_function({ let val = arg; val.isOwned = false; return val.ptr }()) } "#, ) } fn expected_c_header() -> ExpectedCHeader { ExpectedCHeader::ContainsAfterTrim( r#" void __swift_bridge__$some_function(void* arg); "#, ) } #[test] fn extern_rust_fn_arg_vec_of_transparent_enum() { CodegenTest { bridge_module: bridge_module_tokens().into(), expected_rust_tokens: expected_rust_tokens(), expected_swift_code: expected_swift_code(), expected_c_header: expected_c_header(), } .test(); } }
Vec support tests
-
Add a
mod vec_of_transparent_struct
pub(super) mod vec_of_opaque_rust_type; pub(super) mod vec_of_transparent_enum;
-
Model it after the
mod vec_of_transparent_enum
swift-bridge/crates/swift-bridge-ir/src/codegen/generate_rust_tokens/vec/vec_of_transparent_enum.rs
Lines 5 to 12 in 819e391
/// Generate the functions that Swift calls uses inside of the corresponding class for a /// transparent enum's Vectorizable implementation. /// /// So inside of `extension SomeTransparentEnum: Vectorizable {}` on the Swift side. pub(in super::super) fn generate_vec_of_transparent_enum_functions( shared_enum: &SharedEnum, ) -> TokenStream { let enum_name = &shared_enum.name;
-
Same idea with the Swift impl
swift-bridge/crates/swift-bridge-ir/src/codegen/generate_swift/shared_enum.rs
Lines 71 to 102 in 72e1759
extension {enum_name}: Vectorizable {{ public static func vecOfSelfNew() -> UnsafeMutableRawPointer {{ __swift_bridge__$Vec_{enum_name}$new() }} public static func vecOfSelfFree(vecPtr: UnsafeMutableRawPointer) {{ __swift_bridge__$Vec_{enum_name}$drop(vecPtr) }} public static func vecOfSelfPush(vecPtr: UnsafeMutableRawPointer, value: Self) {{ __swift_bridge__$Vec_{enum_name}$push(vecPtr, value.intoFfiRepr()) }} public static func vecOfSelfPop(vecPtr: UnsafeMutableRawPointer) -> Optional<Self> {{ let maybeEnum = __swift_bridge__$Vec_{enum_name}$pop(vecPtr) return maybeEnum.intoSwiftRepr() }} public static func vecOfSelfGet(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional<Self> {{ let maybeEnum = __swift_bridge__$Vec_{enum_name}$get(vecPtr, index) return maybeEnum.intoSwiftRepr() }} public static func vecOfSelfGetMut(vecPtr: UnsafeMutableRawPointer, index: UInt) -> Optional<Self> {{ let maybeEnum = __swift_bridge__$Vec_{enum_name}$get_mut(vecPtr, index) return maybeEnum.intoSwiftRepr() }} public static func vecOfSelfLen(vecPtr: UnsafeMutableRawPointer) -> UInt {{ __swift_bridge__$Vec_{enum_name}$len(vecPtr) }} }}"#
Getting everything working
You should be able to run the tests and tweak code in https://github.com/chinedufn/swift-bridge/blob/2bffcb08c1f0ca8bbcba9c78c5ae28a9cddfb632/crates/swift-bridge-ir/src/bridged_type.rs until the tests pass
If there is currently nobody working on this, I would like to try to implement this (probably next week). |
All yours! |
Unfortunately I got some project deadlines the next weeks that require more work than expected, so I am not able to start working on this any time soon. |
Currently something like the following Swift code:
and this Rust code:
doesn't work, evidently due to the shared struct
Thing
not implmentingVectorizable
on the Swift side. Am I missing something and this sort of thing is possible? If not, could support for this be added?The text was updated successfully, but these errors were encountered: