• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use self::kind::{Kind, Opaque, Trivial};
2 use crate::CxxString;
3 use alloc::string::String;
4 
5 /// A type for which the layout is determined by its C++ definition.
6 ///
7 /// This trait serves the following two related purposes.
8 ///
9 /// <br>
10 ///
11 /// ## Safely unifying occurrences of the same extern type
12 ///
13 /// `ExternType` makes it possible for CXX to safely share a consistent Rust
14 /// type across multiple #\[cxx::bridge\] invocations that refer to a common
15 /// extern C++ type.
16 ///
17 /// In the following snippet, two #\[cxx::bridge\] invocations in different
18 /// files (possibly different crates) both contain function signatures involving
19 /// the same C++ type `example::Demo`. If both were written just containing
20 /// `type Demo;`, then both macro expansions would produce their own separate
21 /// Rust type called `Demo` and thus the compiler wouldn't allow us to take the
22 /// `Demo` returned by `file1::ffi::create_demo` and pass it as the `Demo`
23 /// argument accepted by `file2::ffi::take_ref_demo`. Instead, one of the two
24 /// `Demo`s has been defined as an extern type alias of the other, making them
25 /// the same type in Rust. The CXX code generator will use an automatically
26 /// generated `ExternType` impl emitted in file1 to statically verify that in
27 /// file2 `crate::file1::ffi::Demo` really does refer to the C++ type
28 /// `example::Demo` as expected in file2.
29 ///
30 /// ```no_run
31 /// // file1.rs
32 /// # mod file1 {
33 /// #[cxx::bridge(namespace = "example")]
34 /// pub mod ffi {
35 ///     unsafe extern "C++" {
36 ///         type Demo;
37 ///
38 ///         fn create_demo() -> UniquePtr<Demo>;
39 ///     }
40 /// }
41 /// # }
42 ///
43 /// // file2.rs
44 /// #[cxx::bridge(namespace = "example")]
45 /// pub mod ffi {
46 ///     unsafe extern "C++" {
47 ///         type Demo = crate::file1::ffi::Demo;
48 ///
49 ///         fn take_ref_demo(demo: &Demo);
50 ///     }
51 /// }
52 /// #
53 /// # fn main() {}
54 /// ```
55 ///
56 /// <br><br>
57 ///
58 /// ## Integrating with bindgen-generated types
59 ///
60 /// Handwritten `ExternType` impls make it possible to plug in a data structure
61 /// emitted by bindgen as the definition of a C++ type emitted by CXX.
62 ///
63 /// By writing the unsafe `ExternType` impl, the programmer asserts that the C++
64 /// namespace and type name given in the type id refers to a C++ type that is
65 /// equivalent to Rust type that is the `Self` type of the impl.
66 ///
67 /// ```no_run
68 /// # const _: &str = stringify! {
69 /// mod folly_sys;  // the bindgen-generated bindings
70 /// # };
71 /// # mod folly_sys {
72 /// #     #[repr(transparent)]
73 /// #     pub struct StringPiece([usize; 2]);
74 /// # }
75 ///
76 /// use cxx::{type_id, ExternType};
77 ///
78 /// unsafe impl ExternType for folly_sys::StringPiece {
79 ///     type Id = type_id!("folly::StringPiece");
80 ///     type Kind = cxx::kind::Opaque;
81 /// }
82 ///
83 /// #[cxx::bridge(namespace = "folly")]
84 /// pub mod ffi {
85 ///     unsafe extern "C++" {
86 ///         include!("rust_cxx_bindings.h");
87 ///
88 ///         type StringPiece = crate::folly_sys::StringPiece;
89 ///
90 ///         fn print_string_piece(s: &StringPiece);
91 ///     }
92 /// }
93 ///
94 /// // Now if we construct a StringPiece or obtain one through one
95 /// // of the bindgen-generated signatures, we are able to pass it
96 /// // along to ffi::print_string_piece.
97 /// #
98 /// # fn main() {}
99 /// ```
100 pub unsafe trait ExternType {
101     /// A type-level representation of the type's C++ namespace and type name.
102     ///
103     /// This will always be defined using `type_id!` in the following form:
104     ///
105     /// ```
106     /// # struct TypeName;
107     /// # unsafe impl cxx::ExternType for TypeName {
108     /// type Id = cxx::type_id!("name::space::of::TypeName");
109     /// #     type Kind = cxx::kind::Opaque;
110     /// # }
111     /// ```
112     type Id;
113 
114     /// Either [`cxx::kind::Opaque`] or [`cxx::kind::Trivial`].
115     ///
116     /// [`cxx::kind::Opaque`]: kind::Opaque
117     /// [`cxx::kind::Trivial`]: kind::Trivial
118     ///
119     /// A C++ type is only okay to hold and pass around by value in Rust if its
120     /// [move constructor is trivial] and it has no destructor. In CXX, these
121     /// are called Trivial extern C++ types, while types with nontrivial move
122     /// behavior or a destructor must be considered Opaque and handled by Rust
123     /// only behind an indirection, such as a reference or UniquePtr.
124     ///
125     /// [move constructor is trivial]: https://en.cppreference.com/w/cpp/types/is_move_constructible
126     ///
127     /// If you believe your C++ type reflected by this ExternType impl is indeed
128     /// fine to hold by value and move in Rust, you can specify:
129     ///
130     /// ```
131     /// # struct TypeName;
132     /// # unsafe impl cxx::ExternType for TypeName {
133     /// #     type Id = cxx::type_id!("name::space::of::TypeName");
134     /// type Kind = cxx::kind::Trivial;
135     /// # }
136     /// ```
137     ///
138     /// which will enable you to pass it into C++ functions by value, return it
139     /// by value, and include it in `struct`s that you have declared to
140     /// `cxx::bridge`. Your claim about the triviality of the C++ type will be
141     /// checked by a `static_assert` in the generated C++ side of the binding.
142     type Kind: Kind;
143 }
144 
145 /// Marker types identifying Rust's knowledge about an extern C++ type.
146 ///
147 /// These markers are used in the [`Kind`][ExternType::Kind] associated type in
148 /// impls of the `ExternType` trait. Refer to the documentation of `Kind` for an
149 /// overview of their purpose.
150 pub mod kind {
151     use super::private;
152 
153     /// An opaque type which cannot be passed or held by value within Rust.
154     ///
155     /// Rust's move semantics are such that every move is equivalent to a
156     /// memcpy. This is incompatible in general with C++'s constructor-based
157     /// move semantics, so a C++ type which has a destructor or nontrivial move
158     /// constructor must never exist by value in Rust. In CXX, such types are
159     /// called opaque C++ types.
160     ///
161     /// When passed across an FFI boundary, an opaque C++ type must be behind an
162     /// indirection such as a reference or UniquePtr.
163     pub enum Opaque {}
164 
165     /// A type with trivial move constructor and no destructor, which can
166     /// therefore be owned and moved around in Rust code without requiring
167     /// indirection.
168     pub enum Trivial {}
169 
170     pub trait Kind: private::Sealed {}
171     impl Kind for Opaque {}
172     impl Kind for Trivial {}
173 }
174 
175 mod private {
176     pub trait Sealed {}
177     impl Sealed for super::Opaque {}
178     impl Sealed for super::Trivial {}
179 }
180 
181 #[doc(hidden)]
verify_extern_type<T: ExternType<Id = Id>, Id>()182 pub fn verify_extern_type<T: ExternType<Id = Id>, Id>() {}
183 
184 #[doc(hidden)]
verify_extern_kind<T: ExternType<Kind = Kind>, Kind: self::Kind>()185 pub fn verify_extern_kind<T: ExternType<Kind = Kind>, Kind: self::Kind>() {}
186 
187 macro_rules! impl_extern_type {
188     ($([$kind:ident] $($ty:path = $cxxpath:literal)*)*) => {
189         $($(
190             unsafe impl ExternType for $ty {
191                 #[doc(hidden)]
192                 type Id = crate::type_id!($cxxpath);
193                 type Kind = $kind;
194             }
195         )*)*
196     };
197 }
198 
199 impl_extern_type! {
200     [Trivial]
201     bool = "bool"
202     u8 = "std::uint8_t"
203     u16 = "std::uint16_t"
204     u32 = "std::uint32_t"
205     u64 = "std::uint64_t"
206     usize = "size_t"
207     i8 = "std::int8_t"
208     i16 = "std::int16_t"
209     i32 = "std::int32_t"
210     i64 = "std::int64_t"
211     isize = "rust::isize"
212     f32 = "float"
213     f64 = "double"
214     String = "rust::String"
215 
216     [Opaque]
217     CxxString = "std::string"
218 }
219