-
Notifications
You must be signed in to change notification settings - Fork 355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple FFI blocks referencing types from one another #99
Comments
I've encountered this in my work codebase as well. What we've done for now is declare RawOptionalBaseValue as an opaque C type in both files, and then do unsafe pointer casts from one to the other where necessary: // :(
fn convert(bv: &mut first::ffi::BaseValue) -> &mut second::ffi::BaseValue {
unsafe {
&mut *(bv as *mut first::ffi::BaseValue as *mut second::ffi::BaseValue)
}
} Obviously I'd like to support this better. It needs some more design work but I have some ideas for how to make it work safely and seamlessly, based on treating opaque C types in a way that doesn't produce a distinguishable representation in different places when using the same header and type name: // effectively this, but encoded without relying on const generics
type RawOptionalBaseValue = OpaqueC<"base/values_rust.h", "RawOptionalBaseValue">; |
The part that needs design work is how to deal with codebases in which the same import path might not always refer to the same exact file; in that case allowing the interconversion would be bad. I'm confident it's solvable but just needs some attention. |
Thanks, your workaround worked nicely for me. |
Does anyone know how bindgen deals with the same issue? If we do two bindgen invocations in two different crates but some of the types are in common (something like folly::StringPiece which both crates might use) then do they also have the problem of those becoming two incompatible StringPiece types on the Rust side? I guess they provide a workaround of |
I got a chance to think about this a bit today. I think what I'd like looks more or less like this: // basevalue.rs
#[cxx::bridge(namespace = base)]
pub mod ffi {
extern "C" {
include!("base/values_rust.h");
type RawOptionalBaseValue;
fn /* ... */
}
} // json.rs
#[cxx::bridge(namespace = base)]
pub mod ffi {
extern "C" {
type RawOptionalBaseValue = basevalue::ffi::RawOptionalBaseValue;
fn /* ... */
}
} where the first // same as today
#[repr(C)]
pub struct RawOptionalBaseValue {
_private: ::cxx::private::Opaque,
}
// new
unsafe impl ::cxx::private::ExternType for RawOptionalBaseValue {
type Id = /*type-encoding of "base::RawOptionalBaseValue"*/;
} while the second // assume that they're the same
pub use basevalue::ffi::RawOptionalBaseValue as RawOptionalBaseValue;
// but also enforce that they're the same at compile time
const _: fn() = ::cxx::private::enforce_extern_type_id::<
RawOptionalBaseValue,
/*type-encoding of "base::RawOptionalBaseValue"*/,
>; and in CXX we provide: #[doc(hidden)]
pub fn enforce_extern_type_id<T: ExternType<Id = Id>, Id>() {} The exact type-encoding there for the strings isn't important and I am not particularly worried about figuring out something that will work. Longer term we'll use a "non-type template parameter" a.k.a. "const generic" with the actual string literal, but for now you can conceptualize a possible encoding as:
where each of those is a distinct |
In fact we'd likely end up making the trait unsafe impl cxx::ExternType for folly_sys::StringPiece {
type Id = cxx::type_id!("folly::StringPiece");
} |
I have two files requiring FFI,
json.rs
andbasevalue.rs
. I'd like to keep the FFI blocks local to those files, instead of having a centralffi.rs
, but right now this is not possible.My FFI block in
basevalue.rs
.My FFI block in
json.rs
:Note that the
json.rs
block references a type from thebasevalue.rs
block.This gives
which is unsurprising, and I imagine is really hard to solve.
(The exact code above is significantly simplified so obviously don't try to build it; if this issue isn't as "known" as I expect, let me know and I'll make a minimal test case).
The text was updated successfully, but these errors were encountered: