1
+ use self :: kind:: { Kind , Opaque , Trivial } ;
2
+
1
3
/// A type for which the layout is determined by its C++ definition.
2
4
///
3
5
/// This trait serves the following two related purposes.
69
71
/// # pub struct StringPiece([usize; 2]);
70
72
/// # }
71
73
///
72
- /// use cxx::{type_id, ExternType, Opaque };
74
+ /// use cxx::{type_id, ExternType};
73
75
///
74
76
/// unsafe impl ExternType for folly_sys::StringPiece {
75
77
/// type Id = type_id!("folly::StringPiece");
76
- /// type Kind = Opaque;
78
+ /// type Kind = cxx::kind:: Opaque;
77
79
/// }
78
80
///
79
81
/// #[cxx::bridge(namespace = folly)]
93
95
/// #
94
96
/// # fn main() {}
95
97
/// ```
96
- ///
97
- /// ## Opaque and Trivial types
98
- ///
99
- /// Some C++ types are safe to hold and pass around in Rust, by value.
100
- /// Those C++ types must have a trivial move constructor, and must
101
- /// have no destructor.
102
- ///
103
- /// If you believe your C++ type is indeed trivial, you can specify
104
- /// ```
105
- /// # struct TypeName;
106
- /// # unsafe impl cxx::ExternType for TypeName {
107
- /// type Id = cxx::type_id!("name::space::of::TypeName");
108
- /// type Kind = cxx::Trivial;
109
- /// # }
110
- /// ```
111
- /// which will enable you to pass it into C++ functions by value,
112
- /// return it by value from such functions, and include it in
113
- /// `struct`s that you have declared to `cxx::bridge`. Your promises
114
- /// about the triviality of the C++ type will be checked using
115
- /// `static_assert`s in the generated C++.
116
- ///
117
- /// Opaque types can't be passed by value, but can still be held
118
- /// in `UniquePtr`.
119
98
pub unsafe trait ExternType {
120
99
/// A type-level representation of the type's C++ namespace and type name.
121
100
///
@@ -125,32 +104,80 @@ pub unsafe trait ExternType {
125
104
/// # struct TypeName;
126
105
/// # unsafe impl cxx::ExternType for TypeName {
127
106
/// type Id = cxx::type_id!("name::space::of::TypeName");
128
- /// type Kind = cxx::Opaque;
107
+ /// # type Kind = cxx::kind ::Opaque;
129
108
/// # }
130
109
/// ```
131
110
type Id ;
132
111
133
- /// Either `cxx::Opaque` or `cxx::Trivial`. If in doubt, use
134
- /// `cxx::Opaque`.
135
- type Kind ;
112
+ /// Either [`cxx::kind::Opaque`] or [`cxx::kind::Trivial`].
113
+ ///
114
+ /// [`cxx::kind::Opaque`]: kind::Opaque
115
+ /// [`cxx::kind::Trivial`]: kind::Trivial
116
+ ///
117
+ /// A C++ type is only okay to hold and pass around by value in Rust if its
118
+ /// [move constructor is trivial] and it has no destructor. In CXX, these
119
+ /// are called Trivial extern C++ types, while types with nontrivial move
120
+ /// behavior or a destructor must be considered Opaque and handled by Rust
121
+ /// only behind an indirection, such as a reference or UniquePtr.
122
+ ///
123
+ /// [move constructor is trivial]: https://en.cppreference.com/w/cpp/types/is_move_constructible
124
+ ///
125
+ /// If you believe your C++ type reflected by this ExternType impl is indeed
126
+ /// trivial, you can specify:
127
+ ///
128
+ /// ```
129
+ /// # struct TypeName;
130
+ /// # unsafe impl cxx::ExternType for TypeName {
131
+ /// # type Id = cxx::type_id!("name::space::of::TypeName");
132
+ /// type Kind = cxx::kind::Trivial;
133
+ /// # }
134
+ /// ```
135
+ ///
136
+ /// which will enable you to pass it into C++ functions by value, return it
137
+ /// by value, and include it in `struct`s that you have declared to
138
+ /// `cxx::bridge`. Your claim about the triviality of the C++ type will be
139
+ /// checked by a `static_assert` in the generated C++ side of the binding.
140
+ type Kind : Kind ;
136
141
}
137
142
138
- pub ( crate ) mod kind {
143
+ /// Marker types identifying Rust's knowledge about an extern C++ type.
144
+ ///
145
+ /// These markers are used in the [`Kind`][ExternType::Kind] associated type in
146
+ /// impls of the `ExternType` trait. Refer to the documentation of `Kind` for an
147
+ /// overview of their purpose.
148
+ pub mod kind {
149
+ use super :: private;
150
+
151
+ /// An opaque type which cannot be passed or held by value within Rust.
152
+ ///
153
+ /// Rust's move semantics are such that every move is equivalent to a
154
+ /// memcpy. This is incompatible in general with C++'s constructor-based
155
+ /// move semantics, so a C++ type which has a destructor or nontrivial move
156
+ /// constructor must never exist by value in Rust. In CXX, such types are
157
+ /// called opaque C++ types.
158
+ ///
159
+ /// When passed across an FFI boundary, an opaque C++ type must be behind an
160
+ /// indirection such as a reference or UniquePtr.
161
+ pub enum Opaque { }
162
+
163
+ /// A type with trivial move constructor and no destructor, which can
164
+ /// therefore be owned and moved around in Rust code without requiring
165
+ /// indirection.
166
+ pub enum Trivial { }
139
167
140
- /// An opaque type which can't be passed or held by value within Rust.
141
- /// For example, a C++ type with a destructor, or a non-trivial move
142
- /// constructor. Rust's strict move semantics mean that we can't own
143
- /// these by value in Rust, but they can still be owned by a
144
- /// `UniquePtr`...
145
- pub struct Opaque ;
168
+ pub trait Kind : private:: Sealed { }
169
+ impl Kind for Opaque { }
170
+ impl Kind for Trivial { }
171
+ }
146
172
147
- /// A type with trivial move constructors and no destructor, which
148
- /// can therefore be owned and moved around in Rust code directly.
149
- pub struct Trivial ;
173
+ mod private {
174
+ pub trait Sealed { }
175
+ impl Sealed for super :: Opaque { }
176
+ impl Sealed for super :: Trivial { }
150
177
}
151
178
152
179
#[ doc( hidden) ]
153
180
pub fn verify_extern_type < T : ExternType < Id = Id > , Id > ( ) { }
154
181
155
182
#[ doc( hidden) ]
156
- pub fn verify_extern_kind < T : ExternType < Kind = Kind > , Kind > ( ) { }
183
+ pub fn verify_extern_kind < T : ExternType < Kind = Kind > , Kind : self :: Kind > ( ) { }
0 commit comments