-
Notifications
You must be signed in to change notification settings - Fork 338
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #190 from dtolnay/id
Enable sharing a consistent Rust type across multiple FFI blocks
- Loading branch information
Showing
28 changed files
with
418 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
use proc_macro2::TokenStream; | ||
use quote::{format_ident, quote}; | ||
use syn::LitStr; | ||
|
||
// "folly::File" => `(f, o, l, l, y, (), F, i, l, e)` | ||
pub fn expand(arg: LitStr) -> TokenStream { | ||
let mut ids = Vec::new(); | ||
|
||
for word in arg.value().split("::") { | ||
if !ids.is_empty() { | ||
ids.push(quote!(())); | ||
} | ||
for ch in word.chars() { | ||
ids.push(match ch { | ||
'A'..='Z' | 'a'..='z' => { | ||
let t = format_ident!("{}", ch); | ||
quote!(::cxx::#t) | ||
} | ||
'0'..='9' | '_' => { | ||
let t = format_ident!("_{}", ch); | ||
quote!(::cxx::#t) | ||
} | ||
_ => quote!([(); #ch as _]), | ||
}); | ||
} | ||
} | ||
|
||
quote! { (#(#ids,)*) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/// A type for which the layout is determined by its C++ definition. | ||
/// | ||
/// This trait serves the following two related purposes. | ||
/// | ||
/// <br> | ||
/// | ||
/// ## Safely unifying occurrences of the same extern type | ||
/// | ||
/// `ExternType` makes it possible for CXX to safely share a consistent Rust | ||
/// type across multiple #\[cxx::bridge\] invocations that refer to a common | ||
/// extern C++ type. | ||
/// | ||
/// In the following snippet, two #\[cxx::bridge\] invocations in different | ||
/// files (possibly different crates) both contain function signatures involving | ||
/// the same C++ type `example::Demo`. If both were written just containing | ||
/// `type Demo;`, then both macro expansions would produce their own separate | ||
/// Rust type called `Demo` and thus the compiler wouldn't allow us to take the | ||
/// `Demo` returned by `file1::ffi::create_demo` and pass it as the `Demo` | ||
/// argument accepted by `file2::ffi::take_ref_demo`. Instead, one of the two | ||
/// `Demo`s has been defined as an extern type alias of the other, making them | ||
/// the same type in Rust. The CXX code generator will use an automatically | ||
/// generated `ExternType` impl emitted in file1 to statically verify that in | ||
/// file2 `crate::file1::ffi::Demo` really does refer to the C++ type | ||
/// `example::Demo` as expected in file2. | ||
/// | ||
/// ```no_run | ||
/// // file1.rs | ||
/// # mod file1 { | ||
/// #[cxx::bridge(namespace = example)] | ||
/// pub mod ffi { | ||
/// extern "C" { | ||
/// type Demo; | ||
/// | ||
/// fn create_demo() -> UniquePtr<Demo>; | ||
/// } | ||
/// } | ||
/// # } | ||
/// | ||
/// // file2.rs | ||
/// #[cxx::bridge(namespace = example)] | ||
/// pub mod ffi { | ||
/// extern "C" { | ||
/// type Demo = crate::file1::ffi::Demo; | ||
/// | ||
/// fn take_ref_demo(demo: &Demo); | ||
/// } | ||
/// } | ||
/// # | ||
/// # fn main() {} | ||
/// ``` | ||
/// | ||
/// <br><br> | ||
/// | ||
/// ## Integrating with bindgen-generated types | ||
/// | ||
/// Handwritten `ExternType` impls make it possible to plug in a data structure | ||
/// emitted by bindgen as the definition of an opaque C++ type emitted by CXX. | ||
/// | ||
/// By writing the unsafe `ExternType` impl, the programmer asserts that the C++ | ||
/// namespace and type name given in the type id refers to a C++ type that is | ||
/// equivalent to Rust type that is the `Self` type of the impl. | ||
/// | ||
/// ```no_run | ||
/// # const _: &str = stringify! { | ||
/// mod folly_sys; // the bindgen-generated bindings | ||
/// # }; | ||
/// # mod folly_sys { | ||
/// # #[repr(transparent)] | ||
/// # pub struct StringPiece([usize; 2]); | ||
/// # } | ||
/// | ||
/// use cxx::{type_id, ExternType}; | ||
/// | ||
/// unsafe impl ExternType for folly_sys::StringPiece { | ||
/// type Id = type_id!("folly::StringPiece"); | ||
/// } | ||
/// | ||
/// #[cxx::bridge(namespace = folly)] | ||
/// pub mod ffi { | ||
/// extern "C" { | ||
/// include!("rust_cxx_bindings.h"); | ||
/// | ||
/// type StringPiece = crate::folly_sys::StringPiece; | ||
/// | ||
/// fn print_string_piece(s: &StringPiece); | ||
/// } | ||
/// } | ||
/// | ||
/// // Now if we construct a StringPiece or obtain one through one | ||
/// // of the bindgen-generated signatures, we are able to pass it | ||
/// // along to ffi::print_string_piece. | ||
/// # | ||
/// # fn main() {} | ||
/// ``` | ||
pub unsafe trait ExternType { | ||
/// A type-level representation of the type's C++ namespace and type name. | ||
/// | ||
/// This will always be defined using `type_id!` in the following form: | ||
/// | ||
/// ``` | ||
/// # struct TypeName; | ||
/// # unsafe impl cxx::ExternType for TypeName { | ||
/// type Id = cxx::type_id!("name::space::of::TypeName"); | ||
/// # } | ||
/// ``` | ||
type Id; | ||
} | ||
|
||
#[doc(hidden)] | ||
pub fn verify_extern_type<T: ExternType<Id = Id>, Id>() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.