sonos / ffi-convert-rs Goto Github PK
View Code? Open in Web Editor NEWEasier and safer interface between Rust, C, and other languages
Home Page: https://docs.rs/ffi-convert/
License: Other
Easier and safer interface between Rust, C, and other languages
Home Page: https://docs.rs/ffi-convert/
License: Other
The code here seems to be a weirdly incomplete list of types, missing u8
, i8
and isize
in various places. isize
might be tricky I guess but u8
is pretty annoying because it means I can't use Vec<u8>
which is surely really common?
This is the error you get with Vec<u8>
:
error[E0277]: the trait bound `u8: CReprOf<u8>` is not satisfied
--> src\lib.rs:19:10
|
19 | #[derive(CReprOf, AsRust, CDrop)]
| ^^^^^^^ the trait `CReprOf<u8>` is not implemented for `u8`
|
= help: the following implementations were found:
<u8 as CReprOf<bool>>
= note: required because of the requirements on the impl of `CReprOf<Vec<u8>>` for `CArray<u8>`
= note: required by `c_repr_of`
Unfortunately this is impossible to fix in my code because u8
and CReprOf
aren't defined by me.
Hello,
I'm encountering issue when deriving CreprOf and CDrop on a struct that have a field of type '*const CStringArray'
Like this:
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TestStringArray {
s: Vec<String>,
}
#[derive(Debug, CReprOf, AsRust, CDrop, RawPointerConverter, Clone)]
#[repr(C)]
#[target_type(TestStringArray)]
pub struct TestStringArray_t {
s: *const CStringArray,
}
#[no_mangle]
pub extern "C" fn nodus__msg__TestStringArray_t__create(s: *const CStringArray) -> *mut c_void {
let s = unsafe { CStringArray::as_rust(&*s as &CStringArray).unwrap() };
let msg = TestStringArray { s };
let msg = TestStringArray_t::c_repr_of(msg).unwrap();
Box::into_raw(Box::new(msg)) as *mut c_void
}
#[no_mangle]
pub extern "C" fn nodus__msg__TestStringArray_t__destroy(msg: *mut TestStringArray_t) -> () {
let msg = unsafe { Box::from_raw(msg) };
}
I'm facing these issues:
error[E0599]: no method named `into_raw_pointer` found for struct `CStringArray` in the current scope
--> nodus-bindings/src/generated/msgs/TestStringArray.rs:18:17
|
18 | #[derive(Debug, CReprOf, AsRust, CDrop, RawPointerConverter, Clone)]
| ^^^^^^^ method not found in `CStringArray`
|
= note: this error originates in the derive macro `CReprOf` (in Nightly builds, run with -Z macro-backtrace for more info)
help: one of the expressions' fields has a method of the same name
|
18 | #[derive(Debug, size.CReprOf, AsRust, CDrop, RawPointerConverter, Clone)]
| +++++
error[E0599]: no function or associated item named `drop_raw_pointer` found for struct `CStringArray` in the current scope
--> nodus-bindings/src/generated/msgs/TestStringArray.rs:18:34
|
18 | #[derive(Debug, CReprOf, AsRust, CDrop, RawPointerConverter, Clone)]
| ^^^^^ function or associated item not found in `CStringArray`
|
= note: this error originates in the derive macro `CDrop` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0599`.
error: could not compile `nodus-bindings` due to 2 previous errors
What am i doing wrong ? Could be bug ?
Hello,
Could it be possible to add conversion for fixed size arrays ?
Like:
pub struct Dummy {
a: [u8;4],
b: [i32;12],
...
}
I've created a rust struct generator (using IDL representation format) that create a "pure" rust struct and the repr(C) equivalent.
This coupled with cbindgen and ffi-convert (that are key piece off the whole system, thank you !) allow me to generate a complete "chain" of data exchange C<-->Rust.
Sadly, ffi-convert lacks a feature for me, the fixed array conversion. I want to let the user of my lib create a IDL representing a specific C ABI message (for example a messaging to talk to an external device through serial/udp/tcp...) and let them use (from C) a driver (i created in Rust, on top of udp socket/serial/tcp socket...) that take and return the repr(C) struct corresponding the the IDL struct.
Since the serialization/deserialization can't be done with serde/bincode (because bincode insert the vec length in addition of the inner data) i have to use Bytemuck. But bytemuck only works with Copy types ---> fixed size arrays.
Is it possible to convert between structs and opaque pointers. I want to convert a rust struct that contains a opaque pointer.
I am new to rust so please forgive me if the approach was silly:
libc::c_void
by impl the CReprOf
and AsRust
but it is not posible to implement foreign traint to foreign type.Dear ffi convert team,
I think this example in the docs
#[repr(C)]
pub struct CPizza {
pub name: *const libc::c_char,
pub toppings: *const CArray<CTopping>,
pub base: *const CSauce,
pub weight: libc::c_float,
}
should be?
#[repr(C)]
pub struct CPizza {
pub name: *const libc::c_char,
pub toppings: *const CArray<CTopping>,
#[nullable]
pub base: *const CSauce,
pub weight: libc::c_float,
}
Just discovered this - looks like exactly what I need. I was just a bit confused by this note in the docs:
typedef struct {
const T *values; // Pointer to the value of the list
int32_t size; // Number of T values in the list
} CArrayT;
Shouldn't the type of size
be size_t
? Or at least uint32_t
?
Btw the link to the docs in the readme doesn't go to the latest version.
Hello,
First, is will explain my global application purpose:
I'm generating Rust struct and Rust struct repr(C) from IDL files. I've crated the parser (with Pest) and the dumper (with Tera).
The structures i generate are using this crate.
I need the users to be able to crate their IDLs, and do nothing else than compile to genereate new FFI header and .so where all the structures repr(C) i generated are exposed with cbindgen.
Sad point however, the complex types like CArray are not exposed correctly, it's exposed like:
typedef struct MyStructure_t {
unsigned char var1;
const struct Type1_t *var2;
const CArray<unsigned char> *var3;
const CArray<short> *var4;
const CArray<unsigned char> *var5;
const CArray<short> *var6;
} MyStructure_t;
IDL:
#include "Type1.idl";
struct MyStructure {
@key octet var1;
Type1 var2;
octet var3[9];
short var4[9];
sequence<octet> var5;
sequence<short> var6;
};
File generated from previous IDL:
use std::ffi::*;
use ffi_convert::{AsRust, AsRustError, CArray, CDrop, CReprOf, CReprOfError, RawBorrow, RawPointerConverter};
use serde::{Deserialize, Serialize};
use rustdds::Keyed;
use super::{Type1::Type1,Type1_t};
#[derive(Debug, Serialize, Deserialize)]
pub struct MyStructure {
var1: u8,
var2: Type1,
var3: Vec<u8>,
var4: Vec<i16>,
var5: Vec<u8>,
var6: Vec<i16>,
}
impl MyStructure {
pub fn to_c(self) -> Result<MyStructure_t, CReprOfError> {
let c = MyStructure_t::c_repr_of(self);
c
}
}
impl Keyed for MyStructure {
type K = u8;
fn key(&self) -> Self::K {
self.var1
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, CReprOf, AsRust, CDrop, RawPointerConverter)]
#[repr(C)]
#[target_type(MyStructure)]
pub struct MyStructure_t {
var1: c_uchar,
var2: *const Type1_t,
var3: *const CArray<c_uchar>,
var4: *const CArray<c_short>,
var5: *const CArray<c_uchar>,
var6: *const CArray<c_short>,
}
impl MyStructure_t {
pub fn to_rust(&self) -> Result<MyStructure, AsRustError> {
let pure = self.as_rust();
pure
}
}
How did you do to expose those kind of complex type to C through cbindgen please ?
The examples at the start of ffi-convert/lib.rs
are a little unclear because they hide some use
s and struct
s, notably for ffi_convert::CArray
which makes it harder to discover ffi-convert
by simply copying the examples and going from there.
The section Caveats with derivation of CReprOf and AsRust traits
is also empty, which made me think the published version was not up-to-date with HEAD
.
This crate looks like a good candidate for doing C# <--> Rust ffi through a C API. I will be passing C structs to C# from rust, and then sending those C structs back to rust.
My concern is that I see no way to convert the c struct back to the rust struct efficiently, as AsRust
doesn't take ownership of the C struct. I'm assuming this was done intentionally, but I'm struggling to see why. Is there any way that I can avoid for example deep copying the CArray
? I don't think we can even dereference it right now on the rust side without cloning the data into a Vec
Dear ffi convert team,
I am learning go, rust and the interactions between these 2 languages by consuming rust methods by golang/cgo.
This is my rust code
use ffi_convert::RawBorrow;
use ffi_convert::{AsRust, CArray, CDrop, CReprOf, CStringArray, RawPointerConverter};
use futures::executor::block_on;
use mesa::hsm::group::r#struct::{HsmGroup, Member};
use std::ffi::{c_char, c_float, c_int, c_schar, c_uchar, c_uint, CStr};
#[repr(C)]
#[derive(CReprOf, AsRust, CDrop, RawPointerConverter, Debug)]
#[target_type(Member)]
pub struct CMember {
#[nullable]
ids: *const CStringArray,
}
#[repr(C)]
#[derive(CReprOf, AsRust, CDrop, RawPointerConverter, Debug)]
#[target_type(HsmGroup)]
pub struct CHsmGroup {
label: *const libc::c_char,
#[nullable]
description: *const libc::c_char,
#[nullable]
members: *const CMember,
#[nullable]
exclusive_group: *const libc::c_char,
#[nullable]
tags: *const CStringArray,
}
#[no_mangle]
pub extern "C" fn get_hsm_group(
data: CHsmGroup,
) {
// do something
}
This is my build.rd for dbindgen
extern crate cbindgen;
use std::env;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
cbindgen::Builder::new()
.with_crate(crate_dir)
.generate()
.expect("Unable to generate bindings")
.write_to_file("bindings.h");
}
And this is the headers file generated
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct CMember {
const CStringArray *ids;
} CMember;
typedef struct CHsmGroup {
const char *label;
const char *description;
const struct CMember *members;
const char *exclusive_group;
const CStringArray *tags;
} CHsmGroup;
void get_hsm_group(struct CHsmGroup data);
My understanding is that CStringArray
is not part of the C standard library.
My question is:
How should I use CStringArray
? do I need to import a library in C to use it?
Thank you very much
Hello,
I need CArray to be clone for my 'Message's structures to be Clone as well.
I'm using a dependency that return a reference to a 'Message' when i do a read. The 'Message's struct are behind a generic type M that have a bound Clone on it.
I can use 'to_owned()' on &M to have a M, thanks to the Clone bound.
Is it possible for you to modify CArray to be Clone please ?
The other possibility for me is to require '&self' instead of 'self' in the 'c_repr_of(...)' function.
But the 'Clone' way is less restricting.
Dear ffi convert team,
I am learning go, rust and the interactions between these 2 languages by consuming rust methods by golang.
I have done some tests and I am getting error in cgo trying to understand the header files generated by dbindgen...
This is my rust code
use ffi_convert::RawBorrow;
use ffi_convert::{AsRust, CArray, CDrop, CReprOf, CStringArray, RawPointerConverter};
use futures::executor::block_on;
use mesa::hsm::group::r#struct::{HsmGroup, Member};
use std::ffi::{c_char, c_float, c_int, c_schar, c_uchar, c_uint, CStr};
#[derive(CReprOf, AsRust, CDrop, RawPointerConverter, Debug)]
#[target_type(Member)]
pub struct CMember {
#[nullable]
ids: *const CStringArray,
}
#[repr(C)]
#[derive(CReprOf, AsRust, CDrop, RawPointerConverter, Debug)]
#[target_type(HsmGroup)]
pub struct CHsmGroup {
label: *const libc::c_char,
#[nullable]
description: *const libc::c_char,
#[nullable]
members: *const CMember,
#[nullable]
exclusive_group: *const libc::c_char,
#[nullable]
tags: *const CStringArray,
}
#[no_mangle]
pub extern "C" fn get_hsm_group(
data: CHsmGroup,
) {
// do something
}
This is my build.rd for dbindgen
extern crate cbindgen;
use std::env;
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
cbindgen::Builder::new()
.with_crate(crate_dir)
.generate()
.expect("Unable to generate bindings")
.write_to_file("bindings.h");
}
And this is the headers file generated
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct CMember CMember;
typedef struct CHsmGroup {
const char *label;
const char *description;
const struct CMember *members;
const char *exclusive_group;
const CStringArray *tags;
} CHsmGroup;
void get_hsm_group(struct CHsmGroup data);
I know very little but I think the below may not right?
typedef struct CMember CMember;
I would expect something like below?
typedef struct CMember {
const char *const *ids;
} CMember;
typedef struct CHsmGroup {
const char *label;
const char *description;
const struct CMember *members;
const char *exclusive_group;
const char *const *tags;
} CHsmGroup;
I crated an example here https://github.com/Masber/rust-ffi this creates a shared library that I am using in a Go code, the header file is automatically generated by cbindgen during the build process cargo build --release
Consider using the recently revised Error
trait.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.