Giter Site home page Giter Site logo

Comments (11)

chinedufn avatar chinedufn commented on June 2, 2024

Nevermind. I see that you addressed this in your comment.




Does the implementation of User::current_program_ref return Option<Program> (notice the missing &)?

If so, you'll want something like:

#[swift_bridge::bridge]
mod ffi {
    extern "Rust" {
        type User;
        type Program;

        #[swift_bridge(return_with = Option::as_ref)]
        fn current_program_ref(self: &User) -> Option<&Program>;
    }
}

// Assuming: your code looks like:
impl User {
    fn current_program_ref(&self) -> Option<Program> { unimplemented!() }
}

from swift-bridge.

chinedufn avatar chinedufn commented on June 2, 2024

Ah, it looks like we currently only test returning Option<T>

func testSwiftCallRustWithOptionOpaqueRustType() throws {
let val = OptTestOpaqueRustType(123)
let reflect = rust_reflect_option_opaque_rust_type(val)
XCTAssertEqual(reflect!.field(), 123)
XCTAssertNil(rust_reflect_option_opaque_rust_type(nil))
}

fn rust_reflect_option_opaque_rust_type(
arg: Option<OptTestOpaqueRustType>,
) -> Option<OptTestOpaqueRustType>;

/// Test code generation for Rust function that returns an Option<OpaqueRustType>
mod extern_rust_fn_return_option_opaque_rust_type {
use super::*;
fn bridge_module_tokens() -> TokenStream {
quote! {
mod ffi {
extern "Rust" {
type SomeType;
fn some_function () -> Option<SomeType>;
}
}
}
}
fn expected_rust_tokens() -> ExpectedRustTokens {
ExpectedRustTokens::Contains(quote! {
#[export_name = "__swift_bridge__$some_function"]
pub extern "C" fn __swift_bridge__some_function() -> *mut super::SomeType {
if let Some(val) = super::some_function() {
Box::into_raw(Box::new(val))
} else {
std::ptr::null_mut()
}
}
})
}
fn expected_swift_code() -> ExpectedSwiftCode {
ExpectedSwiftCode::ContainsAfterTrim(
r#"
func some_function() -> Optional<SomeType> {
{ let val = __swift_bridge__$some_function(); if val != nil { return SomeType(ptr: val!) } else { return nil } }()
}
"#,
)
}
fn expected_c_header() -> ExpectedCHeader {
ExpectedCHeader::ContainsAfterTrim(
r#"
void* __swift_bridge__$some_function(void);
"#,
)
}
#[test]
fn extern_rust_fn_return_option_opaque_rust_type() {
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();
}
}


I'd be happy to provide instructions on how to add support for returning Option<&T>. Would boil down to adding a new test case next to each of the ones linked above.

from swift-bridge.

chinedufn avatar chinedufn commented on June 2, 2024

Look like this:

#[export_name = "__swift_bridge__$User$current_program_ref"]
pub extern "C" fn __swift_bridge__User_current_program_ref(
    this: *mut super::User,
) -> *mut super::Program {
    if let Some(val) = (unsafe { &*this }).current_program_ref() {
        Box::into_raw(Box::new(val))
    } else {
        std::ptr::null_mut()
    }
}

Should be:

#[export_name = "__swift_bridge__$User$current_program_ref"]
pub extern "C" fn __swift_bridge__User_current_program_ref(
    this: *mut super::User,
) -> *const super::Program {
    if let Some(val) = (unsafe { &*this }).current_program_ref() {
        val as *const super::Program
    } else {
        std::ptr::null()
    }
}

from swift-bridge.

PrismaPhonic avatar PrismaPhonic commented on June 2, 2024

I was about to say - I just found from experimenting some more that it appears the issue lies in the ref being nested inside the Option. Wow, you're fast!

from swift-bridge.

PrismaPhonic avatar PrismaPhonic commented on June 2, 2024

I can add the new test cases but I would imagine you would be faster at the actual implementation :-P but if you can give instructions for where the translation is happening I can give it a shot

from swift-bridge.

chinedufn avatar chinedufn commented on June 2, 2024

Implementation would go here:

quote! {
if let Some(val) = #expression {
Box::into_raw(Box::new(val))
} else {
std::ptr::null_mut()
}
}

Can replace the linked code with:

let ty = &self.ty;

if self.reference {
    quote! {
        if let Some(val) = #expression {
            val as *const super::#ty
        } else {
            std::ptr::null()
        }
    }
} else {
    quote! {
        if let Some(val) = #expression {
            Box::into_raw(Box::new(val))
        } else {
            std::ptr::null_mut()
        }
    }
}

Please don't hesitate to let me know if you have any questions.

from swift-bridge.

PrismaPhonic avatar PrismaPhonic commented on June 2, 2024

Alright pushed that up: #257

How do I run the full suite of tests?

EDIT: NVM, I see in the README - running now

from swift-bridge.

PrismaPhonic avatar PrismaPhonic commented on June 2, 2024

Hmm, I seem to be hitting this:

error[E0308]: mismatched types
 --> crates/swift-integration-tests/src/option.rs:3:1
  |
3 | #[swift_bridge::bridge]
  | ^^^^^^^^^^^^^^^^^^^^^^^ expected `&OptTestOpaqueRustType`, found `OptTestOpaqueRustType`

Not sure if it's obvious to you from looking at the PR I linked. I would try cargo expand but in this case it expands so much I have trouble finding the relevant code.

Edit: I would guess it probably has something to do with my addition of this:

fn rust_reflect_option_ref_opaque_rust_type(
    arg: Option<&OptTestOpaqueRustType>,
) -> Option<&OptTestOpaqueRustType> {
    arg
}

And then my import for generation:

        fn rust_reflect_option_ref_opaque_rust_type(
            arg: Option<&OptTestOpaqueRustType>,
        ) -> Option<&OptTestOpaqueRustType>;

But I'm not sure why this alone would produce this error as it seems like an extremely simple function and a very simple declaration in the extern "Rust" block

from swift-bridge.

PrismaPhonic avatar PrismaPhonic commented on June 2, 2024

May have found it. I think I needed to also change fn to_ffi_compatible_option_rust_type() in bridged_opaque_type.rs to check the reference as well, and conditionally return either *const or *mut but now I'm getting this:

error[E0308]: mismatched types
   --> crates/swift-integration-tests/src/option.rs:89:13
    |
3   | #[swift_bridge::bridge]
    | ----------------------- arguments to this function are incorrect
...
89  |             arg: Option<&OptTestOpaqueRustType>,
    |             ^^^ types differ in mutability
    |
    = note: expected raw pointer `*mut _`
               found raw pointer `*const OptTestOpaqueRustType`

It seems that the pointer it found is the type we want - I'm not sure why it expects *mut

from swift-bridge.

PrismaPhonic avatar PrismaPhonic commented on June 2, 2024

from cargo expand it looks like the generated code for the test now:

        #[export_name = "__swift_bridge__$rust_reflect_option_ref_opaque_rust_type"]
        pub extern "C" fn __swift_bridge__rust_reflect_option_ref_opaque_rust_type(
            arg: *const super::OptTestOpaqueRustTypeRef,
        ) -> *const super::OptTestOpaqueRustTypeRef {
            if let Some(val) = super::rust_reflect_option_ref_opaque_rust_type(
                if arg.is_null() { None } else { Some(unsafe { *Box::from_raw(arg) }) },
            ) {
                val as *const super::OptTestOpaqueRustTypeRef
            } else {
                std::ptr::null()
            }
        }

It seems to have an issue with from_raw() getting called. I can see that Box::from_raw expects a *mut but I'm not sure what the correct replacement would be here

from swift-bridge.

chinedufn avatar chinedufn commented on June 2, 2024

Thanks for reporting this issue and including clear details. Much appreciated.

I'll reply to any other questions here -> #257

from swift-bridge.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.