|
1 |
| -/// A type for which the layout is determined by its C++ definition. |
| 1 | +/// A type for which the layout is determined by an external definition. |
2 | 2 | ///
|
3 |
| -/// This trait serves the following two related purposes. |
| 3 | +/// `ExternType` makes it possible for CXX to safely share a consistent Rust type across multiple |
| 4 | +/// #\[cxx::bridge\] invocations. This serves multiple related purposes. |
4 | 5 | ///
|
5 | 6 | /// <br>
|
6 | 7 | ///
|
7 |
| -/// ## Safely unifying occurrences of the same extern type |
8 |
| -/// |
9 |
| -/// `ExternType` makes it possible for CXX to safely share a consistent Rust |
10 |
| -/// type across multiple #\[cxx::bridge\] invocations that refer to a common |
11 |
| -/// extern C++ type. |
12 |
| -/// |
13 |
| -/// In the following snippet, two #\[cxx::bridge\] invocations in different |
14 |
| -/// files (possibly different crates) both contain function signatures involving |
15 |
| -/// the same C++ type `example::Demo`. If both were written just containing |
16 |
| -/// `type Demo;`, then both macro expansions would produce their own separate |
17 |
| -/// Rust type called `Demo` and thus the compiler wouldn't allow us to take the |
18 |
| -/// `Demo` returned by `file1::ffi::create_demo` and pass it as the `Demo` |
19 |
| -/// argument accepted by `file2::ffi::take_ref_demo`. Instead, one of the two |
20 |
| -/// `Demo`s has been defined as an extern type alias of the other, making them |
21 |
| -/// the same type in Rust. The CXX code generator will use an automatically |
22 |
| -/// generated `ExternType` impl emitted in file1 to statically verify that in |
23 |
| -/// file2 `crate::file1::ffi::Demo` really does refer to the C++ type |
| 8 | +/// ## Safely unifying occurrences of the same extern C++ type |
| 9 | +/// |
| 10 | +/// In the following snippet, two #\[cxx::bridge\] invocations in different files (possibly |
| 11 | +/// different crates) both contain function signatures involving the same C++ type `example::Demo`. |
| 12 | +/// |
| 13 | +/// If both were written just containing `type Demo;`, then both macro expansions would produce |
| 14 | +/// their own separate Rust type called `Demo` and thus the compiler wouldn't allow us to take the |
| 15 | +/// `Demo` returned by `file1::ffi::create_demo` and pass it as the `Demo` argument accepted by |
| 16 | +/// `file2::ffi::take_ref_demo`. Instead, one of the two `Demo`s has been defined as an extern type |
| 17 | +/// alias of the other, making them the same type in Rust. |
| 18 | +/// |
| 19 | +/// The CXX code generator will use an automatically generated `ExternType` impl emitted in file1 to |
| 20 | +/// statically verify that in file2 `crate::file1::ffi::Demo` really does refer to the C++ type |
24 | 21 | /// `example::Demo` as expected in file2.
|
25 | 22 | ///
|
26 | 23 | /// ```no_run
|
|
53 | 50 | ///
|
54 | 51 | /// ## Integrating with bindgen-generated types
|
55 | 52 | ///
|
56 |
| -/// Handwritten `ExternType` impls make it possible to plug in a data structure |
57 |
| -/// emitted by bindgen as the definition of an opaque C++ type emitted by CXX. |
| 53 | +/// Handwritten `ExternType` impls make it possible to plug in a data structure emitted by bindgen |
| 54 | +/// as the definition of an opaque C++ type emitted by CXX. |
58 | 55 | ///
|
59 |
| -/// By writing the unsafe `ExternType` impl, the programmer asserts that the C++ |
60 |
| -/// namespace and type name given in the type id refers to a C++ type that is |
61 |
| -/// equivalent to Rust type that is the `Self` type of the impl. |
| 56 | +/// By writing the unsafe `ExternType` impl, the programmer asserts that the C++ namespace and type |
| 57 | +/// name given in the type id refers to a C++ type that is equivalent to Rust type that is the |
| 58 | +/// `Self` type of the impl. |
62 | 59 | ///
|
63 | 60 | /// ```no_run
|
64 | 61 | /// # const _: &str = stringify! {
|
|
70 | 67 | /// # }
|
71 | 68 | ///
|
72 | 69 | /// use cxx::{type_id, ExternType};
|
| 70 | +/// use cxx::extern_type; |
73 | 71 | ///
|
74 | 72 | /// unsafe impl ExternType for folly_sys::StringPiece {
|
| 73 | +/// type Kind = extern_type::KindOpaqueCpp; |
75 | 74 | /// type Id = type_id!("folly::StringPiece");
|
76 | 75 | /// }
|
77 | 76 | ///
|
|
93 | 92 | /// # fn main() {}
|
94 | 93 | /// ```
|
95 | 94 | pub unsafe trait ExternType {
|
| 95 | + /// The type's kind. |
| 96 | + /// |
| 97 | + /// Must be either: |
| 98 | + /// * `KindShared` for a shared type declared outside of an extern block in a cxx::bridge, or |
| 99 | + /// * `KindOpqaueCpp` for an opaque C++ type declared inside of an `extern "C"` block. |
| 100 | + /// |
| 101 | + /// Opaque Rust type aliases are unsupported because they can included with a use declaration |
| 102 | + /// and aliased more simply outside of the cxx::bridge. |
| 103 | + type Kind; |
| 104 | + |
96 | 105 | /// A type-level representation of the type's C++ namespace and type name.
|
97 | 106 | ///
|
98 | 107 | /// This will always be defined using `type_id!` in the following form:
|
99 | 108 | ///
|
100 | 109 | /// ```
|
101 | 110 | /// # struct TypeName;
|
102 | 111 | /// # unsafe impl cxx::ExternType for TypeName {
|
| 112 | + /// # type Kind = cxx::extern_type::KindOpaqueCpp; |
103 | 113 | /// type Id = cxx::type_id!("name::space::of::TypeName");
|
104 | 114 | /// # }
|
105 | 115 | /// ```
|
106 | 116 | type Id;
|
107 | 117 | }
|
108 | 118 |
|
| 119 | +pub struct KindOpaqueCpp; |
| 120 | +pub struct KindShared; |
| 121 | + |
109 | 122 | #[doc(hidden)]
|
110 |
| -pub fn verify_extern_type<T: ExternType<Id = Id>, Id>() {} |
| 123 | +pub fn verify_extern_type<T: ExternType<Kind = Kind, Id = Id>, Kind, Id>() {} |
0 commit comments