Skip to content

Commit 799a93a

Browse files
committed
Add Kind associated type to ExternType trait
1 parent 5f5cb84 commit 799a93a

File tree

4 files changed

+43
-29
lines changed

4 files changed

+43
-29
lines changed

macro/src/expand.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ fn expand_cxx_type(namespace: &Namespace, ety: &ExternType) -> TokenStream {
178178
}
179179

180180
unsafe impl ::cxx::ExternType for #ident {
181+
type Kind = ::cxx::extern_type::KindOpaqueCpp;
181182
type Id = #type_id;
182183
}
183184
}
@@ -675,7 +676,7 @@ fn expand_type_alias_verify(namespace: &Namespace, alias: &TypeAlias) -> TokenSt
675676
let end = quote_spanned!(end_span=> >);
676677

677678
quote! {
678-
const _: fn() = #begin #ident, #type_id #end;
679+
const _: fn() = #begin #ident, ::cxx::extern_type::KindOpaqueCpp, #type_id #end;
679680
}
680681
}
681682

src/extern_type.rs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
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.
22
///
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.
45
///
56
/// <br>
67
///
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
2421
/// `example::Demo` as expected in file2.
2522
///
2623
/// ```no_run
@@ -53,12 +50,12 @@
5350
///
5451
/// ## Integrating with bindgen-generated types
5552
///
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.
5855
///
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.
6259
///
6360
/// ```no_run
6461
/// # const _: &str = stringify! {
@@ -70,8 +67,10 @@
7067
/// # }
7168
///
7269
/// use cxx::{type_id, ExternType};
70+
/// use cxx::extern_type;
7371
///
7472
/// unsafe impl ExternType for folly_sys::StringPiece {
73+
/// type Kind = extern_type::KindOpaqueCpp;
7574
/// type Id = type_id!("folly::StringPiece");
7675
/// }
7776
///
@@ -93,18 +92,32 @@
9392
/// # fn main() {}
9493
/// ```
9594
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+
96105
/// A type-level representation of the type's C++ namespace and type name.
97106
///
98107
/// This will always be defined using `type_id!` in the following form:
99108
///
100109
/// ```
101110
/// # struct TypeName;
102111
/// # unsafe impl cxx::ExternType for TypeName {
112+
/// # type Kind = cxx::extern_type::KindOpaqueCpp;
103113
/// type Id = cxx::type_id!("name::space::of::TypeName");
104114
/// # }
105115
/// ```
106116
type Id;
107117
}
108118

119+
pub struct KindOpaqueCpp;
120+
pub struct KindShared;
121+
109122
#[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>() {}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ mod macros;
380380
mod cxx_string;
381381
mod cxx_vector;
382382
mod exception;
383-
mod extern_type;
383+
pub mod extern_type;
384384
mod function;
385385
mod opaque;
386386
mod result;

tests/ui/wrong_type_id.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ error[E0271]: type mismatch resolving `<StringPiece as ExternType>::Id == (f, o,
66
|
77
::: $WORKSPACE/src/extern_type.rs
88
|
9-
| pub fn verify_extern_type<T: ExternType<Id = Id>, Id>() {}
10-
| ------- required by this bound in `verify_extern_type`
9+
| pub fn verify_extern_type<T: ExternType<Kind = Kind, Id = Id>, Kind, Id>() {}
10+
| ------- required by this bound in `verify_extern_type`
1111
|
1212
= note: expected tuple `(f, o, l, l, y, (), B, y, t, e, R, a, n, g, e)`
1313
found tuple `(f, o, l, l, y, (), S, t, r, i, n, g, P, i, e, c, e)`

0 commit comments

Comments
 (0)