I'm trying to generate C header file for a library written in Rust using the rusty-cheddar crate.
Here is the definition and implementation of the struct in Rust:
pub struct AccountDatabase {
money: HashMap<String, u32>,
}
impl AccountDatabase {
fn new() -> AccountDatabase {
AccountDatabase {
money: HashMap::new(),
}
}
}
If I place #[repr(C)] before the struct, rusty-cheddar generates the following declaration of the struct in C
typedef struct AccountDatabase {
HashMap money;
} AccountDatabase;
The HashMap is not known to C, therefore I'd like for the struct to be declared as an opaque pointer.
The solution is specified right on the readme file:
To define an opaque struct you must define a public newtype which is marked as #[repr(C)].
Thus:
struct AccountDatabase {
money: HashMap<String, u32>,
}
impl AccountDatabase {
fn new() -> AccountDatabase {
AccountDatabase {
money: HashMap::new()
}
}
}
#[repr(C)]
pub struct Crate_AccountDatabase(AccountDatabase);
(or with some other struct naming of your choice)
Related
I am working with a framework where structures are defined with underscore first and then structure that is used is created as pointer to that internal structure.
Passing it as argument require additional steps of defining local pointer within the function first.
What is use of this comparing with just declaring structure and using it directly?
//.h
typedef struct _tFoo
{
int value;
} _tFoo;
typedef _tFoo* tFoo;
//.c
void tFoo_setFoo(tFoo* const f, int value)
{
_tFoo* foo = *f;
foo->value = value;
}
What is benefit of having code above comparing with
//.h
typedef struct _tFoo
{
int value;
} tFoo;
//.c
void tFoo_setFoo(tFoo* const f, int value)
{
f->value = value;
}
I would like to store the pointer to a rust struct inside of it's member C struct. Is it required that the struct be enclosed in a Rc rather than a Box?
The reason I'm asking is because although there is shared ownership here, the pointer is only ever accessed from within unsafe member functions of the Rust struct and the C struct's lifetime is tied to that of the enclosing Rust struct.
Here's an example ->
// C struct with constructor/destructor
struct c_foo {
void* internal; // pointer to rust `struct`
/* ... */
};
struct c_foo* c_foo_new();
void c_foo_free(struct c_foo* foo);
// FFI struct generated by bindgen
#[repr(C)]
#[derive(Debug, Copy)]
pub struct Foo {
pub internal: *mut libc::c_void, // pointer to rust `struct`
/* ... */
}
// Rust struct that wraps the FFI struct
struct Bar {
ptr: *mut Foo, // private
/* ... */
}
impl Bar {
fn new() -> Box<Bar> {
unsafe {
let mut bar = Box::new(Bar { ptr: c_foo_new() });
let bar_ptr: *mut ffi::c_void = &mut bar as *mut _ as *mut ffi::c_void;
(*bar.ptr).internal = bar_ptr;
bar
}
}
}
impl Drop for Bar {
fn drop(&mut self) {
unsafe {
c_foo_free((*bar.ptr).internal);
}
}
}
So there's a C struct c_foo with a void * that stores a reference to the Rust struct Bar. Foo is just the bindgen generated Rust wrapper for c_foo.
Do I need a Box or Rc in the Bar::new() function?
To clarify, there is no shared ownership on the Rust side. There is shared ownership b/w the Rust and C side so I guess there is no benefit in using a Rc type.
E_net4 is renamed all the time's comment answers my question -
use Rc only if you need shared ownership in Rust code. Since C does not retain the semantics of this pointer type, C code needs to handle boundaries manually regardless.
I've found https://rust-embedded.github.io/book/interoperability/c-with-rust.html which teaches how to pass a C Struct to Rust. However, it uses the cty crate, which have to be generated by some kind of script.
I want to do things more easily as there is very few things I need to pass. Just some strings (char*) and numbers.
I already sucessfully passed a single uint8_t from C to Rust.
I'm now trying this on the Rust side:
#[repr(C)]
pub struct VPNParameters {
pub address: *mut c_char,
pub address_size: usize,
pub x: c_int,
}
#[no_mangle]
pub extern "C" fn passParameters(vpnParameters: *mut VPNParameters)
{
//error: says "vpnParameters" has no address field
println!("{}", vpnParameters.address);
}
and on C++:
struct VPNParameters {
char* address;
size_t address_size;
int x;
} VPNParameters;
extern "C" void passParameters(VPNParameters* vPNParameters);
I think it's something like that. But why I can't access the struct members on Rust? And possibly it won't work either, I may need to convert the char to a string.
I guess this would work:
println!("{}", unsafe { *vPNParameters.address(i as isize) });
The pointer itself does not have an address field. To "arrive" at the struct that is pointed to, you need to dereference the pointer.
#[repr(C)]
pub struct VPNParameters {
pub address: *mut libc::c_char,
pub address_size: usize,
pub x: libc::c_int,
}
#[no_mangle]
pub extern "C" fn passParameters(vpnParameters: *mut VPNParameters)
{
// Note the asterisk operator
println!("{:?}", unsafe { (*vpnParameters).address });
}
Let's say we have the following code in a .h file:
typedef struct
{
float velocity[2];
float position[2];
float rotation;
} Bullet;
void Bullet_init(Bullet *bullet, float position[2], float velocity[2], float rotation)
{
bullet->rotation = rotation;
bullet->velocity[0] = velocity[0];
bullet->velocity[1] = velocity[1];
bullet->position[0] = position[0];
bullet->position[1] = position[1];
return;
}
If a programmer includes this file in his code, couldn't he simply modify the struct directly with bullet.velocity[2] = 5 instead of using the Bullet_init function? Do we simply need to trust that the programmer will use the functions properly? In C++, you can just create a class with private members that can only be touched with member functions. This isn't that simple with C. Does it even matter?
In C you have to either trust the programmer or make the struct definition not be part of a public interface.
You could for example have (in a header file):
typedef struct some_struct some_struct;
int some_struct_get_member(some_struct * ptr);
void some_struct_set_memember(some_struct * ptr, int newValue);
And then in your .c file:
#include <assert.h>
struct some_struct { int member; };
int some_struct_get_member(struct some_struct * ptr) {
assert(ptr);
return ptr->member;
}
void some_struct_set_member(struct some_struct * ptr, int newValue) {
assert(ptr);
ptr->member = newValue;
}
As for why you might do this, if the struct has complicated internal requirements having it so that only a limited interface manipulates those internals helps ensure that the values always make sense.
I'm having a hard time wrapping my head around declaring mutable (or pointer) variables and interacting with C code through FFI. I've been playing with this for most of the day and have found conflicting examples due to how quickly Rust is developing. :)
The situation is like this: I have a C function which takes in a pointer to a struct, this struct has fields that are ints and char *s. My understanding is that I need to declare a similar struct in Rust to pass to the extern C function.
Here are my example files I've written while trying to figure this out:
main.rs
extern crate libc;
struct testStruct {
an_int: libc::c_int,
a_string: *mut libc::c_char
}
extern {
fn start_test(test: *mut testStruct) -> libc::c_int;
}
fn main() {
// println!("Hello, world!");
let test_struct = testStruct { an_int: 1, a_string: "hello" };
start_test(&mut test_struct);
}
--
test_file.c
#include <stdio.h>
#include "test_file.h"
struct test_struct {
int an_int;
char *a_string;
};
int start_client(struct test_struct *test) {
printf("Test function!\n");
return 0;
}
Obviously the actual code is more complex, I'm just trying to get a basic example working to understand how mutability/pointers work in Rust with FFI.
What is the correct way to declare a structure, or just a variable, in Rust that can be passed to C code expecting a pointer?
The memory layout of a struct is undefined (the compiler is allowed to reorder fields, for instance) unless you add the #[repr(C)] attribute to the struct. This attribute gives the struct a layout compatible with C.
#[repr(C)]
struct TestStruct {
an_int: libc::c_int,
a_string: *mut libc::c_char
}
Using a raw pointer in the struct works fine, but we can do better. There are two other important types in Rust that are only composed of a pointer: borrowed pointers (&'a T or &'a mut T) and Box<T>. You can use these types instead *const T or *mut T to make it clear that the pointer borrows an existing value (and enables the compiler to validate that the pointer doesn't outlive its referent) or points to an object on the heap that should be dropped when the pointer (or the struct containing it) goes out of scope. However, be careful with Box<T>, since you could accidentally free a value while the C code still has a pointer to the value.
#[repr(C)]
struct TestStruct<'a> {
an_int: libc::c_int,
a_string: &'a mut libc::c_char
}
Another thing to watch out for is the use of fat pointers. In Rust, some pointer types are fat, i.e. they carry additional data along with the pointer. For example, slices (*const [T], *mut [T], &'a [T], &'a mut [T]) can be thought of as a struct or tuple containing a pointer to the first item and the number of items in the slice (a usize); trait objects (*const T, *mut T, &'a T, &'a mut T where T is the name of a trait) are composed of a pointer to the object and a pointer to the virtual method table for the trait implementation. You should avoid using these types when defining a Rust struct matching a C struct.
You can find more information on using Rust's FFI in the FFI section of the Rust book.