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

Issues with more complex types #7

Open
runfalk opened this issue Aug 17, 2017 · 3 comments
Open

Issues with more complex types #7

runfalk opened this issue Aug 17, 2017 · 3 comments

Comments

@runfalk
Copy link

runfalk commented Aug 17, 2017

I tried out the library but have been unable to use anything but the simplest types (i32 and bool works). I copied the example project and tested different return values. To compile I use python setup.py build develop


#[no_mangle]
pub unsafe extern "C" fn a_function_from_rust() -> Vec<u8> {
    vec![1, 2, 3]
}

This gives me an error that the function doesn't exist:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "rawloaderpy/__init__.py", line 5, in <module>
    print(lib.a_function_from_rust())
AttributeError: cffi library 'rawloaderpy/_rawloader__lib.so' has no function, constant or global variable named 'a_function_from_rust'

The contents of _rawloader__ffi.py looks like this:

# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('rawloaderpy._rawloader__ffi',
    _version = 0x2601,
    _types = b'',
)

The second issue is with structs:

#[no_mangle]
pub struct Test {
    pub x: i32,
}

#[no_mangle]
pub unsafe extern "C" fn a_function_from_rust() -> Test {
    Test {x: 1}
}

I get the following error message:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "rawloaderpy/__init__.py", line 3, in <module>
    print(lib.a_function_from_rust().x)
TypeError: result type 'struct Test' is opaque

The contents of _rawloader__ffi.py looks like this:

# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('rawloaderpy._rawloader__ffi',
    _version = 0x2601,
    _types = b'\x00\x00\x02\x0D\x00\x00\x00\x0F\x00\x00\x00\x09',
    _globals = (b'\x00\x00\x00\x23a_function_from_rust',0,),
    _struct_unions = ((b'\x00\x00\x00\x02\x00\x00\x00\x10Test',),),
    _typenames = (b'\x00\x00\x00\x02Test',),
)

As far as I can see there is no information about the x field in the struct.

@runfalk
Copy link
Author

runfalk commented Aug 18, 2017

It turns out structs do work if you change the representation to that of a C struct. You need the following code:

#[repr(C)]
pub struct Test {
    pub x: i32,
}

#[no_mangle]
pub unsafe extern "C" fn a_function_from_rust() -> Test {
    Test {x: 1}
}

The #[repr(C)] tells rust to create an equivalent C struct.

I'm gonna update this issue as I discover more and keep it open until things are documented.

@compressed
Copy link

@runfalk For the first issue, you can't return a Vec directly to the python code. You can only return a pointer to it.

Something like this:

#[no_mangle]
pub unsafe extern "C" fn vec_ptr_from_rust() -> *const u8 {
    let v = vec![1, 2, 3];
    let v_ptr = v.as_ptr();
    mem::forget(v);
    v_ptr
}

You need to forget the Vec because otherwise it's lifetime won't live long enough and Rust will drop the vec at the end of the function.

When you're done using the object in Python (e.g. loading it into a numpy array), you'll need to free the memory by exposing another FFI function that calls: drop(Vec::from_raw_parts(ptr, len, len)).

@runfalk
Copy link
Author

runfalk commented Aug 27, 2017

@compressed thank you for your reply. I did figure out a similar solution. I'm using it for a C-wrapper around a rust raw image parsing library: https://github.com/runfalk/pyrawloader/blob/master/rust/src/lib.rs There's an example on how to do the de-allocation function too.

@mitsuhiko would you be interested in a PR with some basic documentation on how to pass common types? If so, which format?

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

No branches or pull requests

2 participants