flapigen-rs
flapigen-rs copied to clipboard
"not yet implemented" for ToString
foreign_interface!(interface ToString {
self_type std::string::ToString;
toString = std::string::ToString::to_string(&self) -> String;
});
thread 'main' panicked at 'not yet implemented', C:\users\spease\.cargo\registry\src\github.com-1ecc6299db9ec823\rust_swig-0.1.3\src\cpp\mod.rs:1303:18
Am I doing something wrong, or is this legitimately not possible? Thanks.
Yes, at the moment it's impossible.
I implemented only support for callbacks that return nothing,
because management of resources that gives C++ to Rust in such way is not clear.
Your example may be transformed by rust_swig to:
struct C_ToString {
....
char * (*toString)(void *opaque);
};
namespace foo {
class ToString {
public:
...
virtual std::string toString() const = 0;
private:
static char * c_toString(void *opaque)
{
auto p = static_cast<ToString *>(opaque);
auto std_string_ret = p->toString();
//TODO: reference to content of std_string_ret becomes invalid after return
// should I allocate and copy and then free in Rust?
}
};
You see, the question is how to manage resources in ToString::c_toString:
should I silently create an extra copy of std::string via malloc and force user to use add extern crate libc; to call free to deallocate memory in impl ToString for C_ToString and then allocate one more time for Rust String, or should I export to C/C++ Rust String allocator?
However, it creates a tricky situation on C++ side where I need to somehow force user to use right allocator.
So you can write only:
foreign_interface!(interface ToString {
self_type std::string::ToString;
toString = std::string::ToString::to_string(&self, _: &str, _: i32, _: &[u32]);
});
almost every type is supported as an input, but none yet as an output for callbacks.
I don't understand what you're saying. If a return type of String is specified, then the function contract is that it's returning an owned string object on the stack. In that case, the equivalent C++ function should have a return type of std::string or QString, not char *.
Even if memory allocation is needed to get the value out of Rust, then the generated function should be able to perform deallocation.
Sorry, @spease I was busy with my day job, I use rust_swig there too,
but for the last few days it was not the top priority.
I don't understand what you're saying.
May be you think about foreign_interface! as the way to call Rust code from C++?
If a return type of String is specified, then the function contract is >that it's returning an owned string object on the stack. In that case, the equivalent C++ function should >have a return type of std::string or QString, not char *.
Even if memory allocation is needed to get the value out of Rust, then the generated function should >be able to perform deallocation.
First of all to make things clear foreign_interface! is the way to callback C++/Java/Lang X code from Rust, not the other way around. So in your case foreign_interface!(interface ToString is the way to get Rust std::string::String from C++,
if you need to get a value out of Rust you need:
foreign_class!(class Fo {
self_type Foo;
method Foo::get(&self) -> String;
});
where struct Foo may look like struct Foo { imp: Box<ToString> }.
In case of foreign_interface! it is supposed to work like this:
Rust:
foreign_interface!(interface ToString {
self_type std::string::ToString;
toString = std::string::ToString::to_string(&self) -> String;
});
fn your_func(x: Box<ToString>) {
let s = x.to_string();
}
foreign_class!(class Boo {
static_method your_func(x: Box<ToString>);
});
and on C++ side:
class MyImpl : public ToString {
public:
std::string to_string() override { implementetion }
};
int main()
{
auto callback = new MyImpl;
auto c_struct_with_function_pointers = MyImpl::to_c_interface(callback);
Boo::your_func(&c_struct_with_function_pointers);
}
Because of Rust being compatible only with C, to call ToString trait implemented on C++ side,
you need (Rust):
impl ToString for CStructWithFunctionPointer {
fn to_string(&self) -> String {
let c_char_ptr: *const c_char = unsafe { (self.to_string)(self.cpp_this) };
//convert CStr to String
libc::free(c_char_ptr);
//return String
}
}
C++
char *c_to_string(void *this)
{
std::string s = static_cast<ToString>(this)->to_string();
char *c_char_ptr = malloc();
memcpy();
return c_char_ptr;
}
As you see, it is possible, but requires extra memory allocation,
so it is impossible to work directly with C++, only via C.
One way to fix this is:
class MyImpl : public ToString {
public:
RustString to_string() override { implementetion }
};
so C++ at start will work with Rust allocated string,
but it requires extending my C++ implementation of RustString.
Nobody asked about this before, but I will think about a way to implement this.