Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 1 | // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| 2 | // Exceptions. See /LICENSE for license information. |
| 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 4 | #![feature(negative_impls, vec_into_raw_parts, extern_types)] |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 5 | //! This crate provides facilities for safely casting across multiple Rust types |
| 6 | //! that represent the same C++ type. This is needed because: |
| 7 | //! |
| 8 | //! - In C++ one can interchangably use references to a forward-declared |
| 9 | //! `struct` and references to the complete definition of the `struct`, but |
| 10 | //! Rust bindings represent them using separate types (see `Incomplete<Name, |
| 11 | //! Declarer>`). |
| 12 | //! |
| 13 | //! - In C++ one can interchangably use multiple independent C++ class template |
| 14 | //! instantiations, but Rust bindings may represent them using separate types. |
| 15 | //! This happens when the same class template is instantiated with the same |
| 16 | //! template arguments in 2 different Crubit-generated crates with C++ |
| 17 | //! bindings. |
| 18 | //! |
| 19 | //! ## Forward declarations |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 20 | //! |
| 21 | //! Given this C++: |
| 22 | //! |
| 23 | //! ```c++ |
| 24 | //! namespace foo { |
| 25 | //! class Foo; |
| 26 | //! } // namespace foo |
| 27 | //! |
| 28 | //! void MyFunction(foo::Foo& foo) { |
| 29 | //! // can pass Foo around, but cannot access members, copy it, delete it, etc. |
| 30 | //! some_other_library::OtherFunction(foo); |
| 31 | //! } |
| 32 | //! ``` |
| 33 | //! |
| 34 | //! We can translate it to this equivalent Rust: |
| 35 | //! |
| 36 | //! ``` |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 37 | //! use forward_declare::{forward_declare, CcCast}; |
| 38 | //! |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 39 | //! forward_declare!(pub Foo = symbol!("foo::Foo")); |
| 40 | //! fn MyFunction(foo: &mut Foo) { |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 41 | //! some_other_library::OtherFunction(foo.cc_cast()); |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 42 | //! } |
| 43 | //! ``` |
| 44 | //! |
| 45 | //! On the reverse end, to **define** a type which may be forward-declared in |
| 46 | //! other crates, use the `unsafe_define!` macro: |
| 47 | //! |
| 48 | //! ``` |
| 49 | //! pub struct Foo { ... } |
Devin Jeanpierre | f40e26b | 2022-04-07 14:48:27 -0700 | [diff] [blame] | 50 | //! unsafe_define!(symbol!("foo::Foo"), Foo); |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 51 | //! ``` |
| 52 | //! |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 53 | //! The C++ forward declaration of a type `class Foo;` declares the name `Foo` |
| 54 | //! to be a type, but does not provide details such size and contents; such type |
| 55 | //! declaration is said to be incomplete. This is used in C++ to speed up build |
| 56 | //! performance (by omitting the real definition from the dependencies) and to |
| 57 | //! break up dependency cycles (by having one or both sides of the cycle |
| 58 | //! forward-declare pieces from the other side). |
| 59 | //! |
| 60 | //! In the general case, forward declarations in existing C++ code cannot be |
| 61 | //! removed without substantial changes. For example, a library can |
| 62 | //! forward-declare a class that is only defined in the binary. So a forward |
| 63 | //! declaration might not even have a single defining type, but one for |
| 64 | //! every binary that uses the library! |
| 65 | //! |
| 66 | //! Rust has close-enough equivalents to forward-declaration for constants and |
| 67 | //! functions, but not for types. This crate can be used wherever forward |
| 68 | //! declarations are used in C++, for those cases where forward declarations |
| 69 | //! cannot be avoided. |
| 70 | //! |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 71 | //! ## Forward Declaring |
| 72 | //! |
| 73 | //! To forward declare a type which supports forward declarations, use the |
| 74 | //! `forward_declare` macro. |
| 75 | //! |
| 76 | //! ``` |
| 77 | //! forward_declare!(pub YourType = symbol!("foo::YourType")); |
| 78 | //! ``` |
| 79 | //! |
| 80 | //! This creates a public alias `pub YourType = |
| 81 | //! Incomplete<symbol!("foo::YourType"), ???>;`, where `???` is some type unique |
| 82 | //! to this scope. In particular, this means that different calls |
| 83 | //! to `forward_declare` produce different (but otherwise interchangeable) |
| 84 | //! types. |
| 85 | //! |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 86 | //! Most user code won't need to directly use the `forward_declare!` macro and |
| 87 | //! can instead rely on forward declarations provided in the `..._rs_api` crates |
| 88 | //! generated by `rs_bindings_from_cc`. |
| 89 | //! |
| 90 | //! ## Providing a full definition |
| 91 | //! |
| 92 | //! For each type you wish to allow to be forward declared by others, give it a |
| 93 | //! globally unique name such as `"foo::YourType"`, and call |
| 94 | //! `unsafe_define!(symbol!("foo::YourType"), YourType)`. |
| 95 | //! |
| 96 | //! Most user code won't need to directly use the `unsafe_define!` macro and can |
| 97 | //! instead rely on definitions provided in the `..._rs_api` crates generated by |
| 98 | //! `rs_bindings_from_cc`. |
| 99 | //! |
| 100 | //! ## Supported casts |
| 101 | //! |
| 102 | //! Casting is supported between |
| 103 | //! |
| 104 | //! * Two forward-declarations of the same C++ type, |
| 105 | //! * A forward-declaration and a complete definition of the same C++ type, |
| 106 | //! * Two complete definitions of the same C++ type (e.g. two identical class |
| 107 | //! template instantiations). |
| 108 | //! |
| 109 | //! ### Pointers and references |
| 110 | //! |
| 111 | //! Casting is also supported for all of the following common pointer types |
| 112 | //! (e.g. a references to a forward-declared type can be cast to a reference to |
| 113 | //! a fully-defined type): |
| 114 | //! |
| 115 | //! * `& _` |
| 116 | //! * `&mut _` |
| 117 | //! * `Pin<& _>` |
| 118 | //! * `Pin<&mut _>` |
| 119 | //! * `* const _` |
| 120 | //! * `* mut _` |
| 121 | //! |
| 122 | //! `Box`, `Rc`, and `Arc` are excluded, because they require knowledge of the |
| 123 | //! `Drop` impl, and incomplete (e.g. forward-declared) types do not know how to |
| 124 | //! drop. |
| 125 | //! |
| 126 | //! Additionally, references can be cast to/from a corresponding `Pin`: |
| 127 | //! |
| 128 | //! * `& T` <-> `Pin<&T>` |
| 129 | //! * `&mut T` <-> `Pin<&mut T>` (only if `T: Unpin`). |
| 130 | //! |
| 131 | //! ### Containers |
| 132 | //! |
| 133 | //! If container's element type supports casting, then casting is also supported |
| 134 | //! for the following container types (e.g. a slice of references to a |
| 135 | //! forward-declared type can be cast to a slice of references to a |
| 136 | //! fully-defined type): |
| 137 | //! |
| 138 | //! * Slices - `&[T]` |
| 139 | //! * Arrays - `[T; N]` |
| 140 | //! * `Vec<T>` |
| 141 | //! * TODO: Add support for more containers as needed (HashSet? bindings for |
| 142 | //! std::vector?) |
| 143 | //! |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 144 | //! ## Passing around values |
| 145 | //! |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 146 | //! Compound data types implement the `CcCast` trait, which allows for |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 147 | //! converting between complete and incomplete types. To convert from complete |
| 148 | //! to incomplete, incomplete to complete, or incomplete to incomplete when |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 149 | //! crossing crate boundaries, use `.cc_cast()` to perform the conversion. |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 150 | //! |
| 151 | //! ``` |
| 152 | //! forward_declare!(pub Foo = symbol!("foo::Foo")); |
| 153 | //! |
| 154 | //! fn takes_incomplete(foo: &mut Foo) { |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 155 | //! some_other_library::other_function(foo.cc_cast()); |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 156 | //! } |
| 157 | //! |
| 158 | //! fn takes_complete(foo: &mut RealFoo) { |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 159 | //! takes_incomplete(foo.cc_cast()); |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 160 | //! } |
| 161 | //! ``` |
| 162 | //! |
| 163 | //! ## Crossing Crate Boundaries |
| 164 | //! |
| 165 | //! **Warning:** Users of incomplete types from other crates should not assume |
| 166 | //! that currently-incomplete types stay incomplete forever; code owners should |
| 167 | //! feel free to replace an incomplete type with a complete type. |
| 168 | //! |
| 169 | //! In Rust, unlike C++, the incomplete type and incomplete type are different |
| 170 | //! types. It is in theory a backwards-incompatible change to change from |
| 171 | //! incomplete to complete. Callers must try as much as possible to ease that |
| 172 | //! transition, since forward declarations are expected to be removed over time. |
| 173 | //! |
| 174 | //! This is partially enforced by the type system: every forward declaration of |
| 175 | //! a type is unique, and every crate should have its own forward declaration, |
| 176 | //! not reusing the forward declaration of another crate. As a result, you must |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 177 | //! call `cc_cast()` when crossing crate boundaries, and failure to do |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 178 | //! so is an error: |
| 179 | //! |
| 180 | //! |
| 181 | //! ```compile_fail |
| 182 | //! # mod other_crate { |
| 183 | //! # forward_declare!(pub ForwardDeclared = symbol!("foo::Type")); |
| 184 | //! # pub fn function(x: &ForwardDeclared) {panic!()} |
| 185 | //! # } |
| 186 | //! |
| 187 | //! forward_declare!(pub ForwardDeclared = symbol!("foo::Type")); |
| 188 | //! let x: &ForwardDeclared = unimplemented!(); |
| 189 | //! other_crate::function(x); // ERROR |
| 190 | //! ``` |
| 191 | //! |
| 192 | //! If that example were valid, then removing a forward declaration and |
| 193 | //! replacing it with the real type would break the caller, requiring a change |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 194 | //! to call `cc_cast()`. But since we always require the caller to call` |
| 195 | //! cc_cast()` *anyway*, even if it already has an incomplete |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 196 | //! type, `other_crate::function` is free to remove the forward declaration |
| 197 | //! without breaking this caller. |
| 198 | //! |
| 199 | //! ```no_run |
| 200 | //! # mod other_crate { |
| 201 | //! # forward_declare!(pub ForwardDeclared = symbol!("foo::Type")); |
| 202 | //! # pub fn function(x: &ForwardDeclared) {panic!()} |
| 203 | //! # } |
| 204 | //! # |
| 205 | //! # forward_declare!(pub ForwardDeclared = symbol!("foo::Type")); |
| 206 | //! # let x: &ForwardDeclared = unimplemented!(); |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 207 | //! other_crate::function(x.cc_cast()); // Works whether `function` takes incomplete or complete type. |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 208 | //! ``` |
| 209 | |
| 210 | pub use forward_declare_proc_macros::*; |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 211 | |
Devin Jeanpierre | 12dfb9a | 2023-01-18 14:54:41 -0800 | [diff] [blame] | 212 | /// Public to be exposed to macros, but otherwise for internal use only. |
| 213 | pub mod internal { |
| 214 | /// `Symbol` type, equivalent to const &'static str values, but usable in |
| 215 | /// generics in stable Rust. |
| 216 | /// |
| 217 | /// Every symbol is a tuple of `C`: for example, `symbol!("xy")` is |
| 218 | /// `Symbol((C<'x'>, C<'y'>))` |
| 219 | #[repr(C)] |
| 220 | pub struct Symbol<T>(std::marker::PhantomData<T>); |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 221 | |
Devin Jeanpierre | 12dfb9a | 2023-01-18 14:54:41 -0800 | [diff] [blame] | 222 | /// A character in a symbol string. |
| 223 | #[repr(C)] |
| 224 | pub struct C<const CHAR: char>; |
| 225 | |
| 226 | /// Types that implement the `CcType` trait with the same `Name` can be |
| 227 | /// safely transmuted between each other, because they either provide |
| 228 | /// bindings for the same C++ type, or point/refer to the same C++ type, |
| 229 | /// or contain the same C++ type. |
| 230 | /// |
| 231 | /// Even though this trait is public, implementations of this trait should |
| 232 | /// only be provided by Crubit itself: |
| 233 | /// |
| 234 | /// - Via `forward_declare!` and `unsafe_define!` macros |
| 235 | /// - Via blanket `impl`s provided for references, pointers (e.g. see `mod |
| 236 | /// ref_transmutability` below). |
Devin Jeanpierre | c7035e4 | 2023-01-18 15:03:42 -0800 | [diff] [blame] | 237 | /// |
| 238 | /// # Safety |
| 239 | /// |
| 240 | /// Two types implement `CcType` with the same name if and only if they can |
| 241 | /// be transmuted to one another. |
Devin Jeanpierre | 12dfb9a | 2023-01-18 14:54:41 -0800 | [diff] [blame] | 242 | pub unsafe trait CcType { |
Devin Jeanpierre | c7035e4 | 2023-01-18 15:03:42 -0800 | [diff] [blame] | 243 | /// `Name` helps Rust type system to identify the given transmutability |
Devin Jeanpierre | 12dfb9a | 2023-01-18 14:54:41 -0800 | [diff] [blame] | 244 | /// equivalence class. |
| 245 | /// |
| 246 | /// `forward_declare!` and `unsafe_define!` macros form the `Name` using |
| 247 | /// the `symbol!` macro, based on the fully-qualified name of |
| 248 | /// the imported C++ type. |
| 249 | /// |
| 250 | /// In other scenarios, the `Name` is formed using an arbitrary |
| 251 | /// convention that is sufficient to guarantee non-overlapping |
| 252 | /// names (e.g. see the private `ref_transmutability::RefName` |
| 253 | /// type alias below). |
| 254 | type Name; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | use internal::*; |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 259 | |
| 260 | extern "C" { |
Devin Jeanpierre | 12dfb9a | 2023-01-18 14:54:41 -0800 | [diff] [blame] | 261 | /// Adding an `Unsized` field to your type makes it completely unsized |
| 262 | /// (not just dynamically-sized). |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 263 | type Unsized; |
| 264 | } |
| 265 | |
| 266 | /// A struct representing an "Incomplete Type" for `Name` |
| 267 | /// |
| 268 | /// For any given name, there may be multiple "incomplete types" for that name |
| 269 | /// -- for example, `Incomplete<symbol!("T"), crate_1::T1>` is a different type |
| 270 | /// from `Incomplete<symbol!("T"), T2>`. This is intentional: in public |
| 271 | /// interfaces, an incomplete type is allowed to be changed to the complete type |
| 272 | /// without breaking callers. |
| 273 | /// |
| 274 | /// TODO(jeanpierreda): make rust think this is ffi-safe. (PhantomData...) |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 275 | #[repr(C)] |
| 276 | pub struct Incomplete<Name, Declarer>(std::marker::PhantomData<(Name, Declarer)>, Unsized); |
| 277 | |
| 278 | // Ensure this is not `Unpin`, `Send`, or `Sync`. This is discussed somewhat in: |
| 279 | // https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs |
| 280 | |
| 281 | /// Incomplete types can't be copied by value, because we don't know their true |
| 282 | /// size. |
| 283 | impl<Name, Declarer> !Unpin for Incomplete<Name, Declarer> {} |
| 284 | /// Similarly, we don't know if they are Send or Sync. |
| 285 | impl<Name, Declarer> !Send for Incomplete<Name, Declarer> {} |
| 286 | impl<Name, Declarer> !Sync for Incomplete<Name, Declarer> {} |
| 287 | |
| 288 | /// Marker trait for complete types. |
| 289 | /// |
| 290 | /// This is automatically implemented for anything `!Unpin`, but all other types |
| 291 | /// need to implement it by hand. Sorry, Rust just doesn't allow the kind of |
| 292 | /// negative reasoning we'd need to make this better. |
| 293 | /// |
| 294 | /// In particular, this is *not* implemented for `Incomplete<...>`. |
| 295 | pub trait Complete {} |
| 296 | |
| 297 | /// We know this to be true because `Incomplete<...>` is `!Unpin`. |
| 298 | /// |
| 299 | /// Ideally we'd get a better blanket impl, but this very nearly covers |
| 300 | /// everything. Most `Unpin` types are going to be wrappers around C++ types, |
| 301 | /// which can auto-generate a `Complete` impl, and the rest are unlikely to |
| 302 | /// matter. |
| 303 | impl<T: Unpin> Complete for T {} |
| 304 | |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 305 | /// All forward declarations represented by `Incomplete<Name, ...>` form a |
| 306 | /// transmutability equivalence class (together with the complete definition(s) |
| 307 | /// - see the `unsafe_define!` macro below). |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 308 | /// |
| 309 | /// # Safety notes |
| 310 | /// |
| 311 | /// We alias references to arbitrary `T` using references to `Incomplete`. This |
| 312 | /// is OK, because of the design of `Incomplete`: |
| 313 | /// |
| 314 | /// - layout: `Incomplete` has no fields of size > 0, so it does not alias `T` |
| 315 | /// incompatibly. |
| 316 | /// |
| 317 | /// - provenance: while in general it is not valid to access memory |
| 318 | /// **neighboring** that of a type (e.g. one can't use &vec[0] to access |
| 319 | /// vec[1]), in this case, we are using `feature(extern_types)`, which is a |
| 320 | /// DST which must grant access to the following memory or else it would be |
| 321 | /// useless. (This type of access is the reason the feature exists). |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 322 | unsafe impl<Name, Declarer> CcType for Incomplete<Name, Declarer> { |
| 323 | type Name = Name; |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 324 | } |
| 325 | |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 326 | /// `unsafe_define!(symbol!("..."), T)` claims that `T` is the unique definition |
| 327 | /// of the type identified by that symbol, and implements the conversions for |
| 328 | /// pointers to and from the corresponding `Incomplete` pointers. |
| 329 | /// |
| 330 | /// Safety: if more than one type claim to be the definition, then they may be |
| 331 | /// transmuted into each other in safe code. The safety requirements for |
| 332 | /// `std::mem::transmute` apply. |
| 333 | // Each `rustfmt` invocation would indent the `type Name...` line further and further to the right. |
| 334 | #[rustfmt::skip] |
| 335 | #[macro_export] |
| 336 | macro_rules! unsafe_define { |
| 337 | // TODO(jeanpierreda): support generic complete type (e.g. `symbol!("xyz") <-> Foo<T> where T : Bar`) |
| 338 | ($Name:ty, $Complete:ty) => { |
Devin Jeanpierre | 12dfb9a | 2023-01-18 14:54:41 -0800 | [diff] [blame] | 339 | unsafe impl $crate::internal::CcType for $Complete { |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 340 | type Name = $Name; |
| 341 | } |
| 342 | }; |
| 343 | } |
| 344 | |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 345 | /// If `T` can be transmuted into `U`, then one can also transmute between |
Lukasz Anforowicz | 0e38532 | 2022-06-30 09:00:50 -0700 | [diff] [blame] | 346 | /// `*const T`, and `* const U`. (This are always "thin" pointers - with the |
| 347 | /// same size as `usize`.) |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 348 | unsafe impl<T: ?Sized> CcType for *const T |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 349 | where |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 350 | T: CcType, |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 351 | { |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 352 | type Name = (*const (), T::Name); |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 353 | } |
| 354 | |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 355 | /// If `T` can be transmuted into `U`, then one can also transmute between `*mut |
Lukasz Anforowicz | 0e38532 | 2022-06-30 09:00:50 -0700 | [diff] [blame] | 356 | /// T`, and `* mut U`. (This are always "thin" pointers - with the same size as |
| 357 | /// `usize`.) |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 358 | unsafe impl<T: ?Sized> CcType for *mut T |
| 359 | where |
| 360 | T: CcType, |
| 361 | { |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 362 | type Name = (*mut (), T::Name); |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 363 | } |
| 364 | |
Lukasz Anforowicz | 0e38532 | 2022-06-30 09:00:50 -0700 | [diff] [blame] | 365 | /// If `T` can be transmuted into `U`, then one can also transmute between |
| 366 | /// arrays `[T; N]` and `[U; N]`. |
| 367 | /// |
| 368 | /// # Safety notes |
| 369 | /// |
| 370 | /// If `T` and `U` are transmutable then they should have the same alignment, |
| 371 | /// size, and stride. Based on "Unsafe Code Guidelines Reference" [1], this |
| 372 | /// means that the arrays `[T; N]` and `[U, N]` have the same memory layout. |
| 373 | /// |
| 374 | /// Note that `T` below has an implicit `T: Sized` constraint. This means that |
| 375 | /// it is *not* possible to transmute into or out-of an array of |
| 376 | /// forward-declared types. OTOH, it *is* possible to transmute between arrays |
| 377 | /// of transmutable, completely-defined/sized types (e.g. between arrays of |
| 378 | /// template instantiations). |
| 379 | /// |
| 380 | /// [1] |
| 381 | /// https://rust-lang.github.io/unsafe-code-guidelines/layout/arrays-and-slices.html#layout-of-rust-array-types |
| 382 | unsafe impl<T, const N: usize> CcType for [T; N] |
| 383 | where |
| 384 | T: CcType, |
| 385 | { |
| 386 | type Name = ([(); N], T::Name); |
| 387 | } |
| 388 | |
| 389 | /// If `T` can be transmuted into `U`, then one can also transmute between |
| 390 | /// slices `[T]` and `[U]`. |
| 391 | /// |
| 392 | /// # Safety notes |
| 393 | /// |
| 394 | /// ## Slices |
| 395 | /// |
| 396 | /// "Unsafe Code Guidelines Reference" [1] points out that "the layout of a |
| 397 | /// slice [T] of length N is the same as that of a [T; N] array". Therefore the |
| 398 | /// safety of slice tranmutability can just depend on the safety of array |
| 399 | /// transmutability and we can just refer to the safety notes for the |
| 400 | /// `impl ... for [T; N]`. |
| 401 | /// |
| 402 | /// [1] |
| 403 | /// https://rust-lang.github.io/unsafe-code-guidelines/layout/arrays-and-slices.html#layout-of-rust-array-types |
| 404 | /// |
| 405 | /// ## References to slices |
| 406 | /// |
| 407 | /// The `impl` below only covers slices `[T]`, but it seems useful to talk here |
| 408 | /// about the safety of transmuting *references* to slices: `&[T]` (covered by |
| 409 | /// the `impl`s in the `ref_transmutability` module below). Transmuting of such |
| 410 | /// "fat" pointers is safe based on "Unsafe Code Guidelines Reference" [2] |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 411 | /// pointing out that the layout of `&[T]` is independent of T - it is expected |
| 412 | /// to have the same layout as: |
Lukasz Anforowicz | 0e38532 | 2022-06-30 09:00:50 -0700 | [diff] [blame] | 413 | /// |
| 414 | /// ```rs |
| 415 | /// #[repr(C)] |
| 416 | /// struct Slice<T> { |
| 417 | /// ptr: *const T, |
| 418 | /// len: usize, |
| 419 | /// } |
| 420 | /// ``` |
| 421 | /// |
| 422 | /// [2] https://rust-lang.github.io/unsafe-code-guidelines/layout/pointers.html#notes |
| 423 | unsafe impl<T> CcType for [T] |
| 424 | where |
| 425 | T: CcType, |
| 426 | { |
| 427 | // Using somewhat icky `usize::MAX` to work around the fact that [()] is |
| 428 | // unsized. |
| 429 | type Name = ([(); usize::MAX], T::Name); |
| 430 | } |
| 431 | |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 432 | /// If `T` can be transmuted into `U`, then one can also transmute between `&'a |
| 433 | /// T`, `&'a U`, `Pin<&'a T>`, and `Pin<&'a U>`. The corresponding CcType uses |
| 434 | /// `RefName` as the `Name` of the transmutability equivalence class. |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 435 | /// |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 436 | /// # Safety |
Devin Jeanpierre | 97a2379 | 2022-04-19 08:17:26 -0700 | [diff] [blame] | 437 | /// |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 438 | /// 1. `&T` => `&U`: Pointers to transmutable things are themselves |
Lukasz Anforowicz | 0e38532 | 2022-06-30 09:00:50 -0700 | [diff] [blame] | 439 | /// transmutable. This is safe for "thin" pointers (e.g. `&i32`) as well as |
| 440 | /// for "fat" pointers (e.g. `&[i32]` also stores the size of the slice). |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 441 | /// |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 442 | /// 2. `&T` => `Pin<&T>`: `Pin` is `repr(transparent)` and `Pin::new` is |
| 443 | /// safe. |
| 444 | /// |
| 445 | /// 3. `Pin<&T>` => `&T`: `Pin` is `repr(transparent)` and `Pin::get_ref` is |
| 446 | /// safe. |
| 447 | /// |
| 448 | /// 4. `Pin<&T>` => `Pin<&U>`: This combines transmutes 3, 1, and 2. |
| 449 | /// |
| 450 | /// 5. `&T` => `Pin<&U>`: This combines transmutes 1 and 2. |
| 451 | /// |
| 452 | /// 6. `Pin<&T>` => `&U`: This combines transmutes 4 and 3. |
| 453 | /// |
| 454 | /// # Transmuting to the unpinned variant |
| 455 | /// |
| 456 | /// We allow transmuting to the unpinned variant, when known to be safe. |
| 457 | /// |
| 458 | /// ## Motivation |
| 459 | /// |
| 460 | /// Consider what happens if a forward declaration in C++ is removed in favor of |
| 461 | /// the complete type, where the library containing that declaration was wrapped |
| 462 | /// in Rust. If the type is trivially relocatable, and we automatically generate |
| 463 | /// C++ bindings which do not use `Pin` except for non-trivially-relocatable |
| 464 | /// types, this would be a backwards incompatible change. So, we should |
| 465 | /// also support unpinning during the cast. |
| 466 | /// |
| 467 | /// ## Limited scope of impls |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 468 | /// |
Devin Jeanpierre | 97a2379 | 2022-04-19 08:17:26 -0700 | [diff] [blame] | 469 | /// Note: ideally we'd blanket impl the conversion to allow unpinning any smart |
| 470 | /// pointer type, and not only mut references, but this causes coherence issues, |
| 471 | /// because `Pin` itself is a smart pointer. I could not think of a workaround |
| 472 | /// that did not require specialization, other than to hardcode the set of |
| 473 | /// pointer types supported. |
| 474 | /// |
| 475 | /// Since we're hardcoding a set of pointer types above *anyway*, we just need |
| 476 | /// to keep the list of unpinnable types in sync with the list of "pointers to |
| 477 | /// transmutable things" above. |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 478 | mod ref_transmutability { |
| 479 | use super::CcType; |
| 480 | use std::pin::Pin; |
| 481 | |
| 482 | type RefName<'a, Name> = (&'a (), Name); |
| 483 | |
| 484 | /// Safety: See the doc comment for the `ref_transmutability` module. |
| 485 | unsafe impl<'a, T: ?Sized> CcType for &'a T |
| 486 | where |
| 487 | T: CcType, |
| 488 | { |
| 489 | type Name = RefName<'a, T::Name>; |
| 490 | } |
| 491 | |
| 492 | /// Safety: See the doc comment for the `ref_transmutability` module. |
| 493 | unsafe impl<'a, T: ?Sized> CcType for Pin<&'a T> |
| 494 | where |
| 495 | T: CcType, |
| 496 | { |
| 497 | type Name = RefName<'a, T::Name>; |
| 498 | } |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 499 | } |
| 500 | |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 501 | /// If `T` can be transmuted into `U`, then one can also transmute |
| 502 | /// 1) between `&'a mut T` and `&'a mut U` |
| 503 | /// 2) between `Pin<&'a mut T>` and `Pin<&'a mut U>` |
| 504 | /// 3) from `&'a mut T` into `Pin<&'a mut T>` or into `Pin<&'a mut U>` |
| 505 | /// |
| 506 | /// Additionally, if `T` and `U` are `Unpin`, then one can also transmute |
| 507 | /// 4) from `Pin<&'a mut T>` into `&'a mut T` or into `&'a mut U` |
| 508 | /// |
| 509 | /// The corresponding CcType uses `MutRefName` as the `Name` of the |
| 510 | /// transmutability equivalence class. |
| 511 | /// |
| 512 | /// # Safety |
| 513 | /// |
| 514 | /// The list below is very similar to the safety notes for `RefName`, except |
| 515 | /// that the 3rd item below also needs to talk about the `T: Unpin` constraint. |
| 516 | /// |
| 517 | /// 1. `&mut T` => `&mut U`: Pointers to transmutable things are themselves |
Lukasz Anforowicz | 0e38532 | 2022-06-30 09:00:50 -0700 | [diff] [blame] | 518 | /// transmutable. This is safe for "thin" pointers (e.g. `&i32`) as well as |
| 519 | /// for "fat" pointers (e.g. `&[i32]` also stores the size of the slice). |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 520 | /// |
| 521 | /// 2. `&mut T` => `Pin<&mut T>`: `Pin` is `repr(transparent)` and `Pin::new` |
| 522 | /// is safe. |
| 523 | /// |
| 524 | /// 3. `Pin<&mut T>` => `&mut T`: `Pin` is `repr(transparent)` and |
| 525 | /// `Pin::into_inner` is safe and allowed for `T: Unpin`. |
| 526 | /// |
| 527 | /// 4. `Pin<&mut T>` => `Pin<&mut U>`: This combines transmutes 3, 1, and 2. |
| 528 | /// |
| 529 | /// 5. `&mut T` => `Pin<&mut U>`: This combines transmutes 1 and 2. |
| 530 | /// |
| 531 | /// 6. `Pin<&mut T>` => `&mut U`: This combines transmutes 4 and 3. |
| 532 | /// |
| 533 | /// # Transmuting to the unpinned variant |
| 534 | /// |
| 535 | /// Transmuting to the unpinned variant is described in more details in the doc |
| 536 | /// comment of `RefName`. |
| 537 | mod mut_ref_transmutability { |
| 538 | use super::CcType; |
| 539 | use std::pin::Pin; |
| 540 | |
| 541 | type MutRefName<'a, Name> = (&'a mut (), Name); |
| 542 | |
| 543 | /// Safety: See the doc comment for the `mut_ref_transmutability` module. |
| 544 | unsafe impl<'a, T: ?Sized> CcType for &'a mut T |
| 545 | where |
| 546 | T: CcType, |
| 547 | T: Unpin, // See safety notes for MutRefName, item 3 |
| 548 | { |
| 549 | type Name = MutRefName<'a, T::Name>; |
| 550 | } |
| 551 | |
| 552 | /// Safety: See the doc comment for the `mut_ref_transmutability` module. |
| 553 | unsafe impl<'a, T: ?Sized> CcType for Pin<&'a mut T> |
| 554 | where |
| 555 | T: CcType, |
| 556 | { |
| 557 | type Name = MutRefName<'a, T::Name>; |
| 558 | } |
| 559 | } |
| 560 | |
| 561 | /// Like `Into<T>`, but for completeness conversions. |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 562 | pub trait CcCast<T> { |
| 563 | fn cc_cast(self) -> T; |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 564 | } |
| 565 | |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 566 | impl<T, U> CcCast<U> for T |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 567 | where |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 568 | T: CcType, |
| 569 | U: CcType<Name = T::Name>, |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 570 | { |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 571 | fn cc_cast(self) -> U { |
Lukasz Anforowicz | 79fdd2d | 2022-06-30 08:57:58 -0700 | [diff] [blame] | 572 | assert_eq!(std::mem::size_of::<T>(), std::mem::size_of::<U>()); |
| 573 | let x = std::mem::ManuallyDrop::new(self); |
| 574 | unsafe { std::mem::transmute_copy(&*x) } |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 575 | } |
| 576 | } |
| 577 | |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 578 | impl<'a, T: ?Sized, U: ?Sized> CcCast<Vec<&'a U>> for Vec<&'a T> |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 579 | where |
Lukasz Anforowicz | 511d3f8 | 2022-06-30 08:39:45 -0700 | [diff] [blame] | 580 | T: CcType, |
| 581 | U: CcType<Name = T::Name>, |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 582 | { |
Lukasz Anforowicz | bdc54be | 2022-06-30 10:47:21 -0700 | [diff] [blame] | 583 | fn cc_cast(self) -> Vec<&'a U> { |
Devin Jeanpierre | 3dd5f4d | 2022-03-31 02:18:36 -0700 | [diff] [blame] | 584 | let (p, len, capacity) = self.into_raw_parts(); |
| 585 | unsafe { Vec::from_raw_parts(p as *mut &'a U, len, capacity) } |
| 586 | } |
| 587 | } |