I have some c functions with a struct pointer argument.
extern "C" {
fn InitSomeStruct() -> *SomeStruct;
fn SomeFunction(v: *SomeStruct);
fn DestroySomeStruct(v: *SomeStruct);
}
fn main() {
unsafe {
let s = InitSomeStruct();
SomeFunction(s);
DestroySomeStruct(s);
}
}
The implementation of SomeStruct is unknown.
How to declare and use external struct like SomeStruct from the rust code?
The convention is to use an empty enum for opaque FFI types, that is:
enum SomeStruct {}
An empty struct like struct SomeStruct; is also used sometimes.
Related
Is there a way to retrieve public constants from the inner struct in the Newtype pattern?
Say I am using a struct from another crate like this
#[derive(PartialEq)]
pub struct Version(u32);
impl Version {
pub const v0: Self = Self(0);
pub const v1: Self = Self(1);
}
Now, in my code I need to wrap it with a newtype pattern. So far so good.
#[derive(PartialEq)]
pub struct MyVersion(Version);
I want to get the inner constant using the wrapper type along the lines of MyVersion::v0. Is this doable?
Rust Playground link
Thanks to #Sven for suggesting a solution that works with stable Rust.
A way out of this is to implement a trait with an associated type. The end usage is awkward (due to E0223), but at least re-defining constants and associated methods is unnecessary.
// original crate
#[derive(Debug, PartialEq)]
pub struct Version(u32);
impl Version {
pub const V0: Self = Self(0);
pub const V1: Self = Self(1);
}
// another crate
use std::ops::Deref;
#[derive(Debug, PartialEq)]
pub struct MyVersion(Version);
impl Deref for MyVersion {
type Target = Version;
fn deref(&self) -> &Self::Target {
&self.0
}
}
trait Versioning {
type V;
}
impl Versioning for MyVersion {
type V = Version;
}
fn main() {
let myv0 = MyVersion(Version::V0);
assert_eq!(*myv0, <MyVersion as Versioning>::V::V0);
}
The custom trait will probably not be needed when inherent associated type lands in the stable channel.
Say, for purposes of conjecture, that you have three files: main.rs, struct.rs, and impl.rs. Could you define a struct in struct.rs, put an impl there, put another impl in impl.rs, and then use both sets of impls from main.rs? If so, how?
Project structure:
main.rs:
use struct;
use impl;
main() {
let foobar = struct::Struct::new(); // defined in struct.rs
foobar.x(); // defined in impl.rs
}
struct.rs:
Define Struct, first impl
impl.rs:
Second impl
Yes, this is possible. You can provide implementations for your struct throughout the crate. You just can't provide impls for types from foreign crates. And you don't need to do anything special to make this work – just make sure the struct is visible in main. Of course you can't name your modules struct and impl, since these are reserved words.
Here's some example code:
fn main() {
use struct_::A;
A::foo();
A::bar();
}
pub mod struct_ {
pub struct A;
impl A {
pub fn foo() {}
}
}
mod impl_ {
impl crate::struct_::A {
pub fn bar() {}
}
}
(Playground)
I'm trying to create and return a C++ struct. I am currently getting a cannot move out of dereference of raw pointer error when I try to compile. Any idea how I can make this work?
#![allow(non_snake_case)]
#![allow(unused_variables)]
extern crate octh;
// https://thefullsnack.com/en/string-ffi-rust.html
use std::ffi::CString;
#[no_mangle]
pub unsafe extern "C" fn Ghelloworld(
shl: *const octh::root::octave::dynamic_library,
relative: bool,
) -> *mut octh::root::octave_dld_function {
let name = CString::new("helloworld").unwrap();
let pname = name.as_ptr() as *const octh::root::std::string;
std::mem::forget(pname);
let doc = CString::new("Hello World Help String").unwrap();
let pdoc = doc.as_ptr() as *const octh::root::std::string;
std::mem::forget(pdoc);
return octh::root::octave_dld_function_create(Some(Fhelloworld), shl, pname, pdoc);
}
pub unsafe extern "C" fn Fhelloworld(
args: *const octh::root::octave_value_list,
nargout: ::std::os::raw::c_int,
) -> octh::root::octave_value_list {
let list: *mut octh::root::octave_value_list = ::std::ptr::null_mut();
octh::root::octave_value_list_new(list);
std::mem::forget(list);
return *list;
}
I'm trying to create and return a C++ struct
You cannot; C++ (like Rust) does not have a stable, defined ABI. There is no way in Rust to specify that a structure has repr(C++), therefore you cannot create such a structure, much less return it.
The only stable ABI is the one presented by C. You can define structs as repr(C) to be able to return them directly:
extern crate libc;
use std::ptr;
#[repr(C)]
pub struct ValueList {
id: libc::int32_t,
}
#[no_mangle]
pub extern "C" fn hello_world() -> ValueList {
let list_ptr = ::std::ptr::null_mut();
// untested, will cause segfault unless list_ptr is set
unsafe { ptr::read(list_ptr) }
}
That method is highly suspicious though; normally you'd see it as
#[no_mangle]
pub extern "C" fn hello_world() -> ValueList {
unsafe {
let mut list = mem::uninitialized();
list_initialize(&mut list);
list
}
}
See also:
Is it possible to use a C++ library from Rust when the library uses templates (generics)?
I encourage you to read my Rust FFI Omnibus.
Given a struct:
#[repr(C)]
pub struct User {
pub name: *const c_char,
pub age: u8,
pub ctx: ??,
}
the field ctx would only be manipulated by C code; it's a pointer to a C struct UserAttr.
According to the Rust FFI documentation, the choice would be defined as an opaque type pub enum UserAttr {}. However, I found that Rust is unable to copy its value, e.g. why does the address of an object change across methods.
What's the right way in Rust to define such an opaque pointer, so that its value (as a pointer) gets copied across methods?
The future
RFC 1861 introduced the concept of an extern type. While implemented, it is not yet stabilized. Once it is, it will become the preferred implementation:
#![feature(extern_types)]
extern "C" {
type Foo;
}
type FooPtr = *mut Foo;
Today
The documentation states:
To do this in Rust, let’s create our own opaque types:
#[repr(C)] pub struct Foo { private: [u8; 0] }
#[repr(C)] pub struct Bar { private: [u8; 0] }
extern "C" {
pub fn foo(arg: *mut Foo);
pub fn bar(arg: *mut Bar);
}
By including a private field and no constructor, we create an opaque
type that we can’t instantiate outside of this module. An empty array
is both zero-size and compatible with #[repr(C)]. But because our
Foo and Bar types are different, we’ll get type safety between the
two of them, so we cannot accidentally pass a pointer to Foo to
bar().
An opaque pointer is created such that there's no normal way of creating such a type; you can only create pointers to it.
mod ffi {
use std::ptr;
pub struct MyTypeFromC { _private: [u8; 0] }
pub fn constructor() -> *mut MyTypeFromC {
ptr::null_mut()
}
pub fn something(_thing: *mut MyTypeFromC) {
println!("Doing a thing");
}
}
use ffi::*;
struct MyRustType {
score: u8,
the_c_thing: *mut MyTypeFromC,
}
impl MyRustType {
fn new() -> MyRustType {
MyRustType {
score: 42,
the_c_thing: constructor(),
}
}
fn something(&mut self) {
println!("My score is {}", self.score);
ffi::something(self.the_c_thing);
self.score += 1;
}
}
fn main() {
let mut my_thing = MyRustType::new();
my_thing.something();
}
Breaking it down a bit:
// opaque -----V~~~~~~~~~V
*mut MyTypeFromC
// ^~~^ ------------ pointer
Thus it's an opaque pointer. Moving the struct MyRustType will not change the value of the pointer.
The past
Previous iterations of this answer and the documentation suggested using an empty enum (enum MyTypeFromC {}). An enum with no variants is semantically equivalent to the never type (!), which is a type that cannot exist. There were concerns that using such a construct could lead to undefined behavior, so moving to an empty array was deemed safer.
Suppose I have the following Rust library:
// lib.rs
#![crate_type = staticlib]
#[no_mangle]
pub extern fn do_something(number: i32) {
// something
}
#[no_mangle]
pub extern fn do_something_else(collection: &Vec<i32>) {
// something
}
I know that, to call do_something from C, I'd just need to declare an extern function taking an int32_t, but is it possible to call do_something_else? If so, how?
You can, but the better question is should you?
Since you cannot construct a Vec from C, you'd have to construct it in Rust and then return a pointer to C. C code would own the pointer to the Vec and would then pass it back when calling do_something_else.
Then there's the problem that you can't really modify the Vec in C either, other than by creating new FFI methods that mirror all of the Rust methods.
You also probably shouldn't take a &Vec<i32> because Rust references are guaranteed to not be NULL, and there's nothing that enforces that when called from C. It's better to take a *const Vec<i32>, assert that it's non-NULL and convert it to a reference.
Chances are that you want to accept a C array through the FFI boundary. C arrays are a pointer and a length, so you'd accept both and reconstitute a Rust slice (since you wouldn't own the array):
use std::slice;
pub extern fn do_something_else(p: *const i32, len: libc::size_t) {
let slice = unsafe {
assert!(!p.is_null());
slice::from_raw_parts(p, len)
};
}
Obligatory link to The Rust FFI Omnibus.
If you really needed to do what you asked, it would probably look something like this:
extern crate libc;
#[no_mangle]
pub extern fn make_vec() -> *mut Vec<i32> {
Box::into_raw(Box::new(Vec::new()))
}
#[no_mangle]
pub extern fn add_number(vec: *mut Vec<i32>, val: libc::int32_t) {
let vec = unsafe {
assert!(!vec.is_null());
&mut *vec
};
vec.push(val);
}
#[no_mangle]
pub extern fn print_vec(vec: *const Vec<i32>) {
let vec = unsafe {
assert!(!vec.is_null());
&*vec
};
println!("{:?}", vec);
}
#[no_mangle]
pub extern fn drop_vec(vec: *mut Vec<i32>) {
unsafe {
assert!(!vec.is_null());
Box::from_raw(vec);
}
}
And would be used like (untested):
// Add extern declarations
int main(int argc, char *argv[]) {
void *v = make_vec(); // Use a real typedef here
add_number(v, 42);
print_vec(v);
drop_vec(v);
}
You'd want to run this under valgrind to make sure I didn't do anything stupid memory-wise.