5

I am building a Rust library that needs to call some C functions with Rust objects. I have a trait with a function that calls the C function, the C function is defined in Rust as follows:

extern {
    fn process_trait(my_trait: MyTrait);
}

The idea is that the user can implement the trait for his struct and then call the C functions (basically, the C then calls some other Rust back, which calls some of the Trait functions). The error here is: the trait core::marker::Sized is not implemented for the type Self, because I am passing *self to process_trait. Am I doing something wrong? I tried changing this a bit, even casting, I am getting either this error or wrong type.

I think the problem is that it's supposed to be heap allocated, no? The only thing I am trying to avoid is the API looking ugly. The user should just be able to

struct MyUnit;
impl MyTrait for MyUnit...
MyUnit.callC();
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
User
  • 51
  • 3

1 Answers1

2

Passing a trait object by value doesn't make sense, especially when interacting with C. The actual type (in the C sense) and its size is not known, and there's no vtable inside the object. You most likely want to pass a trait reference (&MyTrait). However, traits are foreign to C and thus make a bad interface. While you could define the equivalent of core::raw::TraitObject in C, actually doing anything with the vtable is extremely ugly and fragile and unsafe.

If you need polymorphism across the Rust-C barrier, explicit function pointers are a much better option. You can still have MyTrait and the callC method, it's just the FFI parts that look different. It may be possible to hand the C library callbacks with the objects as payload.

Alternatively, pass around the aforementioned TraitObjects (fat pointers) but never inspect them from C, call methods through (non-trait) helper function in Rust:

extern fn call_method(obj: TraitObject) {
    let obj: &MyTrait = transmute(obj); // should be safe, but not tested
    obj.meth();
}

This avoids the trouble that is manually digging through a Rust vtable in C.

  • I am not that big of an expert, so I probably don't understand much of what you wrote here, but I do have a comment about the end. C doesn't interact in any way with the data except creating the bridge between the Rust code (which has callbacks). I am going to test this method, but it seems like the right stuff (judging by the explanation). Thanks – User Apr 02 '15 at 18:13
  • But how do I integrate this `TraitObject` code into my trait function? – User Apr 02 '15 at 18:18
  • @User That code doesn't belong into any trait. It's a *free-standing* function that allows C code to invoke a method on a `&MyTrait` without knowing how Rust implements method calls on trait objects. –  Apr 02 '15 at 19:03
  • I think you misunderstood, C code doesn't need to interact with the trait, it just needs to pass the trait to a rust callback – User Apr 02 '15 at 19:19
  • @User Please add more a more concrete description of what you're trying to do (and in which language) to the question. Pseudo code examples or such. I have a hard time visualizing exactly what problem you run into. –  Apr 02 '15 at 19:21
  • Code with no trait object: http://is.gd/yCJ2SU Code with: http://is.gd/VkMeSs Both don't compile – User Apr 02 '15 at 19:28
  • @User The important part is what the C code is doing with the `Scope`. And that `any_function(param: MyTrait)` doesn't work has nothing to do with C or the FFI. –  Apr 02 '15 at 19:46
  • seems like I asked on the IRC and I have an answer now, it just needs some testing, thanks for your answer though :) – User Apr 02 '15 at 19:55