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

Support Option<Vec<T>> where T is primitive #147

Merged
merged 3 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,19 @@ class OptionTests: XCTestCase {
XCTAssertNil(rust_reflect_option_str(none))
}

func testSwiftCallRustWithOptionVecOfPrimitiveType() throws {
let vec = RustVec<UInt16>()
vec.push(value: 123)
vec.push(value: 321)
let reflected = rust_reflect_option_vector_rust_type(vec)
XCTAssertEqual(reflected!.len(), 2)

XCTAssertEqual(reflected!.get(index: 0), 123)
XCTAssertEqual(reflected!.get(index: 1), 321)

XCTAssertNil(rust_reflect_option_vector_rust_type(nil))
}

func testSwiftCallRustWithOptionOpaqueRustType() throws {
let val = OptTestOpaqueRustType(123)
let reflect = rust_reflect_option_opaque_rust_type(val)
Expand Down
5 changes: 3 additions & 2 deletions crates/swift-bridge-ir/src/bridged_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -888,8 +888,9 @@ impl BridgedType {
StdLibType::Str => {
quote! { #swift_bridge_path::string::RustStr }
}
StdLibType::Vec(_) => {
todo!("Option<Vec<T>> is not yet supported")
StdLibType::Vec(ty) => {
let ty = ty.ty.to_rust_type_path();
quote! { *mut Vec<#ty> }
}
StdLibType::Option(_) => {
todo!("Option<Option<T>> is not yet supported")
Expand Down
27 changes: 20 additions & 7 deletions crates/swift-bridge-ir/src/bridged_type/bridged_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,13 @@ impl BridgedOption {
}
Copy link
Owner

Choose a reason for hiding this comment

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

Awesome work in this file

}
StdLibType::Vec(_) => {
todo!("Support Option<Vec<T>>")
quote! {
if let Some(value) = #expression {
Box::into_raw(Box::new(value))
} else {
std::ptr::null_mut()
}
}
}
StdLibType::Option(_) => {
todo!("Support Option<Option<T>>")
Expand Down Expand Up @@ -154,7 +160,9 @@ impl BridgedOption {
}
}
StdLibType::Vec(_) => {
todo!("Option<Vec<T>> is not yet supported")
quote! {
if #expression.is_null() { None } else { Some( unsafe { * Box::from_raw(#expression) } ) }
}
}
StdLibType::Option(_) => {
todo!("Option<Option<T>> is not yet supported")
Expand Down Expand Up @@ -214,7 +222,11 @@ impl BridgedOption {
)
}
StdLibType::Vec(_) => {
todo!("Support Option<Vec<T>>")
format!(
"{{ let val = {expression}; if val != nil {{ return RustVec(ptr: val!) }} else {{ return nil }} }}()"
,
expression = expression
)
}
StdLibType::Option(_) => {
todo!("Support Option<Option<T>>")
Expand Down Expand Up @@ -280,7 +292,10 @@ impl BridgedOption {
format!("{expression}AsRustStr", expression = expression)
}
StdLibType::Vec(_) => {
todo!("Option<Vec<T> is not yet supported")
format!(
"{{ if let val = {expression} {{ val.isOwned = false; return val.ptr }} else {{ return nil }} }}()"
, expression = expression
)
}
StdLibType::Option(_) => {
todo!("Option<Option<T> is not yet supported")
Expand Down Expand Up @@ -340,9 +355,7 @@ impl BridgedOption {
todo!("Option<&[T]> is not yet supported")
}
StdLibType::Str => "struct RustStr".to_string(),
StdLibType::Vec(_) => {
todo!("Option<Vec<T>> is not yet supported")
}
StdLibType::Vec(_) => "void*".to_string(),
StdLibType::Option(_) => {
todo!("Option<Option<T>> is not yet supported")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,70 @@ struct __private__OptionF32 __swift_bridge__$some_function(struct __private__Opt
}
}

/// Test code generation for Rust function that accepts and returns an Option<Vec<T>> where T is a
/// primitive.
mod extern_rust_fn_option_vector_primitive {
use super::*;

fn bridge_module_tokens() -> TokenStream {
quote! {
mod ffi {
extern "Rust" {
fn some_function (arg: Option<Vec<i32>>) -> Option<Vec<u32>>;
}
}
}
}

fn expected_rust_tokens() -> ExpectedRustTokens {
ExpectedRustTokens::Contains(quote! {
#[export_name = "__swift_bridge__$some_function"]
pub extern "C" fn __swift_bridge__some_function(
arg: *mut Vec<i32>
) -> *mut Vec<u32> {
if let Some(value) = super::some_function(
if arg.is_null() {
None
} else {
Some( unsafe { * Box::from_raw(arg) } )
}
) {
Box::into_raw(Box::new(value))
} else {
std::ptr::null_mut()
}
}
})
}

fn expected_swift_code() -> ExpectedSwiftCode {
ExpectedSwiftCode::ContainsAfterTrim(
r#"
public func some_function(_ arg: Optional<RustVec<Int32>>) -> Optional<RustVec<UInt32>> {
{ let val = __swift_bridge__$some_function({ if let val = arg { val.isOwned = false; return val.ptr } else { return nil } }()); if val != nil { return RustVec(ptr: val!) } else { return nil } }()
}
"#,
)
}

const EXPECTED_C_HEADER: ExpectedCHeader = ExpectedCHeader::ExactAfterTrim(
r#"
void* __swift_bridge__$some_function(void* arg);
"#,
);

#[test]
fn extern_rust_fn_option_vector_primitive() {
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();
}
}

/// Test code generation for Rust function that accepts and returns Option<String>.
mod extern_rust_fn_option_string {
use super::*;
Expand Down
7 changes: 6 additions & 1 deletion crates/swift-integration-tests/src/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ mod ffi {
fn rust_reflect_option_bool(arg: Option<bool>) -> Option<bool>;

fn rust_reflect_option_string(arg: Option<String>) -> Option<String>;

fn rust_create_option_static_str() -> Option<&'static str>;
fn rust_reflect_option_str(arg: Option<&str>) -> Option<&str>;

fn rust_reflect_option_vector_rust_type(arg: Option<Vec<u16>>) -> Option<Vec<u16>>;

fn rust_reflect_option_opaque_rust_type(
arg: Option<OptTestOpaqueRustType>,
) -> Option<OptTestOpaqueRustType>;
Expand Down Expand Up @@ -192,6 +193,10 @@ fn rust_reflect_option_str(arg: Option<&str>) -> Option<&str> {
arg
}

fn rust_reflect_option_vector_rust_type(arg: Option<Vec<u16>>) -> Option<Vec<u16>> {
arg
}

fn rust_reflect_option_opaque_rust_type(
arg: Option<OptTestOpaqueRustType>,
) -> Option<OptTestOpaqueRustType> {
Expand Down