blob: 041bd72770be3dc839b297de940542d90a24a991 [file] [log] [blame]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07001// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009use core::{marker::PhantomData, ops::Deref, pin::Pin};
10
11#[cfg(nightly)]
12use std::{marker::Unsize, ops::DispatchFromDyn};
13
14use cxx::{memory::UniquePtrTarget, UniquePtr};
15
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070016/// A C++ const reference. These are different from Rust's `&T` in that
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070017/// these may exist even while the object is mutated elsewhere. See also
18/// [`CppMutRef`] for the mutable equivalent.
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070019///
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070020/// The key rule is: we *never* dereference these in Rust. Therefore, any
21/// UB here cannot manifest within Rust, but only across in C++, and therefore
22/// they are equivalently safe to using C++ references in pure-C++ codebases.
23///
24/// *Important*: you might be wondering why you've never encountered this type.
25/// These exist in autocxx-generated bindings only if the `unsafe_references_wrapped`
26/// safety policy is given. This may become the default in future.
27///
28/// # Usage
29///
30/// These types of references are pretty useless in Rust. You can't do
31/// field access. But, you can pass them back into C++! And specifically,
32/// you can call methods on them (i.e. use this type as a `this`). So
33/// the common case here is when C++ gives you a reference to some type,
34/// then you want to call methods on that reference.
35///
36/// # Calling methods
37///
38/// As noted, one of the main reasons for this type is to call methods.
39/// Unfortunately, that depends on unstable Rust features. If you can't
40/// call methods on one of these references, check you're using nightly
41/// and add `#![feature(arbitrary_self_types)]` to your crate.
42///
43/// # Lifetimes and cloneability
44///
45/// Although these references implement C++ aliasing semantics, they
46/// do attempt to give you Rust lifetime tracking. This means if a C++ object
47/// gives you a reference, you won't be able to use that reference after the
48/// C++ object is no longer around.
49///
50/// This is usually what you need, since a C++ object will typically give
51/// you a reference to part of _itself_ or something that it owns. But,
52/// if you know that the returned reference lasts longer than its vendor,
53/// you can use `lifetime_cast` to get a long-lived version.
54///
55/// On the other hand, these references do not give you Rust's exclusivity
56/// guarantees. These references can be freely cloned, and using [`CppRef::const_cast`]
57/// you can even make a mutable reference from an immutable reference.
58///
59/// # Field access
60///
61/// Field access would be achieved by adding C++ `get` and/or `set` methods.
62/// It's possible that a future version of `autocxx` could generate such
63/// getters and setters automatically, but they would need to be `unsafe`
64/// because there is no guarantee that the referent of a `CppRef` is actually
65/// what it's supposed to be, or alive. `CppRef`s may flow from C++ to Rust
66/// via arbitrary means, and with sufficient uses of `get` and `set` it would
67/// even be possible to create a use-after-free in pure Rust code (for instance,
68/// store a [`CppPin`] in a struct field, get a `CppRef` to its referent, then
69/// use a setter to reset that field of the struct.)
70///
71/// # Deref
72///
73/// This type implements [`Deref`] because that's the mechanism that the
74/// unstable Rust `arbitrary_self_types` features uses to determine callable
75/// methods. However, actually calling `Deref::deref` is not permitted and will
76/// result in a compilation failure. If you wish to create a Rust reference
77/// from the C++ reference, see [`CppRef::as_ref`].
78///
79/// # Nullness
80///
81/// Creation of a null C++ reference is undefined behavior (because such
82/// a reference can only be created by dereferencing a null pointer.)
83/// However, in practice, they exist, and we need to be compatible with
84/// pre-existing C++ APIs even if they do naughty things like this.
85/// Therefore this `CppRef` type does allow null values. This is a bit
86/// unfortunate because it means `Option<CppRef<T>>`
87/// occupies more space than `CppRef<T>`.
88///
89/// # Dynamic dispatch
90///
91/// You might wonder if you can do this:
92/// ```ignore
93/// let CppRef<dyn Trait> = ...; // obtain some CppRef<concrete type>
94/// ```
95/// Dynamic dispatch works so long as you're using nightly (we require another
96/// unstable feature, `dispatch_from_dyn`). But we need somewhere to store
97/// the trait object, and `CppRef` isn't it -- a `CppRef` can only store a
98/// simple pointer to something else. So, you need to store the trait object
99/// in a `Box` or similar:
100/// ```ignore
101/// trait SomeTrait {
102/// fn some_method(self: CppRef<Self>)
103/// }
104/// impl SomeTrait for ffi::Concrete {
105/// fn some_method(self: CppRef<Self>) {}
106/// }
107/// let obj: Pin<Box<dyn SomeTrait>> = ffi::Concrete::new().within_box();
108/// let obj = CppPin::from_pinned_box(obj);
109/// farm_area.as_cpp_ref().some_method();
110/// ```
111///
112/// # Implementation notes
113///
114/// Internally, this is represented as a raw pointer in Rust. See the note above
115/// about Nullness for why we don't use [`core::ptr::NonNull`].
116#[repr(transparent)]
117pub struct CppRef<'a, T: ?Sized> {
118 ptr: *const T,
119 phantom: PhantomData<&'a T>,
120}
121
122impl<'a, T: ?Sized> CppRef<'a, T> {
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700123 /// Retrieve the underlying C++ pointer.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700124 pub fn as_ptr(&self) -> *const T {
125 self.ptr
126 }
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700127
128 /// Get a regular Rust reference out of this C++ reference.
129 ///
130 /// # Safety
131 ///
132 /// Callers must guarantee that the referent is not modified by any other
133 /// C++ or Rust code while the returned reference exists. Callers must
134 /// also guarantee that no mutable Rust reference is created to the
135 /// referent while the returned reference exists.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700136 ///
137 /// Callers must also be sure that the C++ reference is properly
138 /// aligned, not null, pointing to valid data, etc.
139 pub unsafe fn as_ref(&self) -> &T {
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700140 &*self.as_ptr()
141 }
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700142
143 /// Create a C++ reference from a raw pointer.
144 pub fn from_ptr(ptr: *const T) -> Self {
145 Self {
146 ptr,
147 phantom: PhantomData,
148 }
149 }
150
151 /// Create a mutable version of this reference, roughly equivalent
152 /// to C++ `const_cast`.
153 ///
154 /// The opposite is to use [`AsCppRef::as_cpp_ref`] on a [`CppMutRef`]
155 /// to obtain a [`CppRef`].
156 ///
157 /// # Safety
158 ///
159 /// Because we never dereference a `CppRef` in Rust, this cannot create
160 /// undefined behavior _within Rust_ and is therefore not unsafe. It is
161 /// however generally unwise, just as it is in C++. Use sparingly.
162 pub fn const_cast(&self) -> CppMutRef<'a, T> {
163 CppMutRef {
164 ptr: self.ptr as *mut T,
165 phantom: self.phantom,
166 }
167 }
168
169 /// Extend the lifetime of the returned reference beyond normal Rust
170 /// borrow checker rules.
171 ///
172 /// Normally, a reference can't be used beyond the lifetime of the object
173 /// which gave it to you, but sometimes C++ APIs can return references
174 /// to global or other longer-lived objects. In such a case you should
175 /// use this method to get a longer-lived reference.
176 ///
177 /// # Usage
178 ///
179 /// When you're given a C++ reference and you know its referent is valid
180 /// for a long time, use this method. Store the resulting `PhantomReferent`
181 /// somewhere in Rust with an equivalent lifetime.
182 /// That object can then vend longer-lived `CppRef`s using
183 /// [`AsCppRef::as_cpp_ref`].
184 ///
185 /// # Safety
186 ///
187 /// Because `CppRef`s are never dereferenced in Rust, misuse of this API
188 /// cannot lead to undefined behavior _in Rust_ and is therefore not
189 /// unsafe. Nevertheless this can lead to UB in C++, so use carefully.
190 pub fn lifetime_cast(&self) -> PhantomReferent<T> {
191 PhantomReferent(self.ptr)
192 }
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700193}
194
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700195impl<'a, T: ?Sized> Deref for CppRef<'a, T> {
196 type Target = *const T;
197 #[inline]
198 fn deref(&self) -> &Self::Target {
199 // With `inline_const` we can simplify this to:
200 // const { panic!("you shouldn't deref CppRef!") }
201 struct C<T: ?Sized>(T);
202 impl<T: ?Sized> C<T> {
203 const V: core::convert::Infallible = panic!(
204 "You cannot directly obtain a Rust reference from a CppRef. Use CppRef::as_ref."
205 );
206 }
207 match C::<T>::V {}
208 }
209}
210
211impl<'a, T: ?Sized> Clone for CppRef<'a, T> {
212 fn clone(&self) -> Self {
213 Self {
214 ptr: self.ptr,
215 phantom: self.phantom,
216 }
217 }
218}
219
220#[cfg(nightly)]
221impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<CppRef<'_, U>> for CppRef<'_, T> {}
222
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700223/// A C++ non-const reference. These are different from Rust's `&mut T` in that
224/// several C++ references can exist to the same underlying data ("aliasing")
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700225/// and that's not permitted for regular Rust references.
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700226///
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700227/// See [`CppRef`] for details on safety, usage models and implementation.
228///
229/// You can convert this to a [`CppRef`] using the [`std::convert::Into`] trait.
230#[repr(transparent)]
231pub struct CppMutRef<'a, T: ?Sized> {
232 ptr: *mut T,
233 phantom: PhantomData<&'a T>,
234}
235
236impl<'a, T: ?Sized> CppMutRef<'a, T> {
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700237 /// Retrieve the underlying C++ pointer.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700238 pub fn as_mut_ptr(&self) -> *mut T {
239 self.ptr
240 }
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700241
242 /// Get a regular Rust mutable reference out of this C++ reference.
243 ///
244 /// # Safety
245 ///
246 /// Callers must guarantee that the referent is not modified by any other
247 /// C++ or Rust code while the returned reference exists. Callers must
248 /// also guarantee that no other Rust reference is created to the referent
249 /// while the returned reference exists.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700250 ///
251 /// Callers must also be sure that the C++ reference is properly
252 /// aligned, not null, pointing to valid data, etc.
253 pub unsafe fn as_mut(&mut self) -> &mut T {
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700254 &mut *self.as_mut_ptr()
255 }
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700256
257 /// Create a C++ reference from a raw pointer.
258 pub fn from_ptr(ptr: *mut T) -> Self {
259 Self {
260 ptr,
261 phantom: PhantomData,
262 }
263 }
264
265 /// Extend the lifetime of the returned reference beyond normal Rust
266 /// borrow checker rules. See [`CppRef::lifetime_cast`].
267 pub fn lifetime_cast(&mut self) -> PhantomReferentMut<T> {
268 PhantomReferentMut(self.ptr)
269 }
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700270}
271
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700272impl<'a, T: ?Sized> Deref for CppMutRef<'a, T> {
273 type Target = *const T;
274 #[inline]
275 fn deref(&self) -> &Self::Target {
276 // With `inline_const` we can simplify this to:
277 // const { panic!("you shouldn't deref CppRef!") }
278 struct C<T: ?Sized>(T);
279 impl<T: ?Sized> C<T> {
280 const V: core::convert::Infallible = panic!("You cannot directly obtain a Rust reference from a CppMutRef. Use CppMutRef::as_mut.");
281 }
282 match C::<T>::V {}
283 }
284}
285
286impl<'a, T: ?Sized> Clone for CppMutRef<'a, T> {
287 fn clone(&self) -> Self {
288 Self {
289 ptr: self.ptr,
290 phantom: self.phantom,
291 }
292 }
293}
294
295impl<'a, T> From<CppMutRef<'a, T>> for CppRef<'a, T> {
296 fn from(mutable: CppMutRef<'a, T>) -> Self {
297 Self {
298 ptr: mutable.ptr,
299 phantom: mutable.phantom,
300 }
301 }
302}
303
304#[cfg(nightly)]
305impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<CppMutRef<'_, U>> for CppMutRef<'_, T> {}
306
307/// Any type which can return a C++ reference to its contents.
308pub trait AsCppRef<T: ?Sized> {
309 /// Returns a reference which obeys C++ reference semantics
310 fn as_cpp_ref(&self) -> CppRef<T>;
311}
312
313/// Any type which can return a C++ reference to its contents.
314pub trait AsCppMutRef<T: ?Sized>: AsCppRef<T> {
315 /// Returns a mutable reference which obeys C++ reference semantics
316 fn as_cpp_mut_ref(&mut self) -> CppMutRef<T>;
317}
318
319impl<'a, T: ?Sized> AsCppRef<T> for CppMutRef<'a, T> {
320 fn as_cpp_ref(&self) -> CppRef<T> {
321 CppRef::from_ptr(self.ptr)
322 }
323}
324
325/// Workaround for the inability to use std::ptr::addr_of! on the contents
326/// of a box.
327#[repr(transparent)]
328struct CppPinContents<T: ?Sized>(T);
329
330impl<T: ?Sized> CppPinContents<T> {
331 fn addr_of(&self) -> *const T {
332 std::ptr::addr_of!(self.0)
333 }
334 fn addr_of_mut(&mut self) -> *mut T {
335 std::ptr::addr_of_mut!(self.0)
336 }
337}
338
339/// A newtype wrapper which causes the contained object to obey C++ reference
340/// semantics rather than Rust reference semantics. That is, multiple aliasing
341/// mutable C++ references may exist to the contents.
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700342///
343/// C++ references are permitted to alias one another, and commonly do.
344/// Rust references must alias according only to the narrow rules of the
345/// borrow checker.
346///
347/// If you need C++ to access your Rust object, first imprison it in one of these
348/// objects, then use [`Self::as_cpp_ref`] to obtain C++ references to it.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700349/// If you need the object back for use in the Rust domain, use [`CppPin::extract`],
350/// but be aware of the safety invariants that you - as a human - will need
351/// to guarantee.
352///
353/// # Usage models
354///
355/// From fairly safe to fairly unsafe:
356///
357/// * *Configure a thing in Rust then give it to C++*. Take your Rust object,
358/// set it up freely using Rust references, methods and data, then imprison
359/// it in a `CppPin` and keep it around while you work with it in C++.
360/// There is no possibility of _aliasing_ UB in this usage model, but you
361/// still need to be careful of use-after-free bugs, just as if you were
362/// to create a reference to any data in C++. The Rust borrow checker will
363/// help you a little by ensuring that your `CppRef` objects don't outlive
364/// the `CppPin`, but once those references pass into C++, it can't help.
365/// * *Pass a thing to C++, have it operate on it synchronously, then take
366/// it back*. To do this, you'd imprison your Rust object in a `CppPin`,
367/// then pass mutable C++ references (using [`AsCppMutRef::as_cpp_mut_ref`])
368/// into a C++ function. C++ would duly operate on the object, and thereafter
369/// you could reclaim the object with `extract()`. At this point, you (as
370/// a human) will need to give a guarantee that no references remain in the
371/// C++ domain. If your object was just locally used by a single C++ function,
372/// which has now returned, this type of local analysis may well be practical.
373/// * *Share a thing between Rust and C++*. This object can vend both C++
374/// references and Rust references (via `as_ref` etc.) It may be possible
375/// for you to guarantee that C++ does not mutate the object while any Rust
376/// reference exists. If you choose this model, you'll need to carefully
377/// track exactly what happens to references and pointers on both sides,
378/// and document your evidence for why you are sure this is safe.
379/// Failure here is bad: Rust makes all sorts of optimization decisions based
380/// upon its borrow checker guarantees, so mistakes can lead to undebuggable
381/// action-at-a-distance crashes.
382///
383/// # See also
384///
385/// See also [`CppUniquePtrPin`], which is equivalent for data which is in
386/// a [`cxx::UniquePtr`].
387pub struct CppPin<T: ?Sized>(Box<CppPinContents<T>>);
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700388
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700389impl<T: ?Sized> CppPin<T> {
390 /// Imprison the Rust data within a `CppPin`. This eliminates any remaining
391 /// Rust references (since we take the item by value) and this object
392 /// subsequently only vends C++ style references, not Rust references,
393 /// until or unless `extract` is called.
394 pub fn new(item: T) -> Self
395 where
396 T: Sized,
397 {
398 Self(Box::new(CppPinContents(item)))
399 }
400
401 /// Imprison the boxed Rust data within a `CppPin`. This eliminates any remaining
402 /// Rust references (since we take the item by value) and this object
403 /// subsequently only vends C++ style references, not Rust references,
404 /// until or unless `extract` is called.
405 ///
406 /// If the item is already in a `Box`, this is slightly more efficient than
407 /// `new` because it will avoid moving/reallocating it.
408 pub fn from_box(item: Box<T>) -> Self {
409 // Safety: CppPinContents<T> is #[repr(transparent)] so
410 // this transmute from
411 // Box<T>
412 // to
413 // Box<CppPinContents<T>>
414 // is safe.
415 let contents = unsafe { std::mem::transmute(item) };
416 Self(contents)
417 }
418
419 // Imprison the boxed Rust data within a `CppPin`. This eliminates any remaining
420 /// Rust references (since we take the item by value) and this object
421 /// subsequently only vends C++ style references, not Rust references,
422 /// until or unless `extract` is called.
423 ///
424 /// If the item is already in a `Box`, this is slightly more efficient than
425 /// `new` because it will avoid moving/reallocating it.
426 pub fn from_pinned_box(item: Pin<Box<T>>) -> Self {
427 // Safety: it's OK to un-pin the Box because we'll be putting it
428 // into a CppPin which upholds the same pinned-ness contract.
429 Self::from_box(unsafe { Pin::into_inner_unchecked(item) })
430 }
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700431
432 /// Get an immutable pointer to the underlying object.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700433 pub fn as_ptr(&self) -> *const T {
434 self.0.addr_of()
435 }
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700436
437 /// Get a mutable pointer to the underlying object.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700438 pub fn as_mut_ptr(&mut self) -> *mut T {
439 self.0.addr_of_mut()
440 }
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700441
442 /// Get a normal Rust reference to the underlying object. This is unsafe.
443 ///
444 /// # Safety
445 ///
446 /// You must guarantee that C++ will not mutate the object while the
447 /// reference exists.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700448 pub unsafe fn as_ref(&self) -> &T {
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700449 &*self.as_ptr()
450 }
451
452 /// Get a normal Rust mutable reference to the underlying object. This is unsafe.
453 ///
454 /// # Safety
455 ///
456 /// You must guarantee that C++ will not mutate the object while the
457 /// reference exists.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700458 pub unsafe fn as_mut(&mut self) -> &mut T {
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700459 &mut *self.as_mut_ptr()
460 }
Austin Schuh6ea9bfa2023-08-06 19:05:10 -0700461
462 /// Extract the object from within its prison, for re-use again within
463 /// the domain of normal Rust references.
464 ///
465 /// This returns a `Box<T>`: if you want the underlying `T` you can extract
466 /// it using `*`.
467 ///
468 /// # Safety
469 ///
470 /// Callers promise that no remaining C++ references exist either
471 /// in the form of Rust [`CppRef`]/[`CppMutRef`] or any remaining pointers/
472 /// references within C++.
473 pub unsafe fn extract(self) -> Box<T> {
474 // Safety: CppPinContents<T> is #[repr(transparent)] so
475 // this transmute from
476 // Box<CppPinContents<T>>
477 // to
478 // Box<T>
479 // is safe.
480 std::mem::transmute(self.0)
481 }
482}
483
484impl<T: ?Sized> AsCppRef<T> for CppPin<T> {
485 fn as_cpp_ref(&self) -> CppRef<T> {
486 CppRef::from_ptr(self.as_ptr())
487 }
488}
489
490impl<T: ?Sized> AsCppMutRef<T> for CppPin<T> {
491 fn as_cpp_mut_ref(&mut self) -> CppMutRef<T> {
492 CppMutRef::from_ptr(self.as_mut_ptr())
493 }
494}
495
496/// Any newtype wrapper which causes the contained [`UniquePtr`] target to obey C++ reference
497/// semantics rather than Rust reference semantics. That is, multiple aliasing
498/// mutable C++ references may exist to the contents.
499///
500/// C++ references are permitted to alias one another, and commonly do.
501/// Rust references must alias according only to the narrow rules of the
502/// borrow checker.
503pub struct CppUniquePtrPin<T: UniquePtrTarget>(UniquePtr<T>);
504
505impl<T: UniquePtrTarget> CppUniquePtrPin<T> {
506 /// Imprison the type within a `CppPin`. This eliminates any remaining
507 /// Rust references (since we take the item by value) and this object
508 /// subsequently only vends C++ style references, not Rust references.
509 pub fn new(item: UniquePtr<T>) -> Self {
510 Self(item)
511 }
512
513 /// Get an immutable pointer to the underlying object.
514 pub fn as_ptr(&self) -> *const T {
515 // TODO - avoid brief reference here
516 self.0
517 .as_ref()
518 .expect("UniquePtr was null; we can't make a C++ reference")
519 }
520}
521
522impl<T: UniquePtrTarget> AsCppRef<T> for CppUniquePtrPin<T> {
523 fn as_cpp_ref(&self) -> CppRef<T> {
524 CppRef::from_ptr(self.as_ptr())
525 }
526}
527
528impl<T: UniquePtrTarget> AsCppMutRef<T> for CppUniquePtrPin<T> {
529 fn as_cpp_mut_ref(&mut self) -> CppMutRef<T> {
530 let pinnned_ref: Pin<&mut T> = self
531 .0
532 .as_mut()
533 .expect("UniquePtr was null; we can't make a C++ reference");
534 let ptr = unsafe { Pin::into_inner_unchecked(pinnned_ref) };
535 CppMutRef::from_ptr(ptr)
536 }
537}
538
539/// A structure used to extend the lifetime of a returned C++ reference,
540/// to indicate to Rust that it's beyond the normal Rust lifetime rules.
541/// See [`CppRef::lifetime_cast`].
542#[repr(transparent)]
543pub struct PhantomReferent<T: ?Sized>(*const T);
544
545impl<T: ?Sized> AsCppRef<T> for PhantomReferent<T> {
546 fn as_cpp_ref(&self) -> CppRef<T> {
547 CppRef::from_ptr(self.0)
548 }
549}
550
551/// A structure used to extend the lifetime of a returned C++ mutable reference,
552/// to indicate to Rust that it's beyond the normal Rust lifetime rules.
553/// See [`CppRef::lifetime_cast`].
554#[repr(transparent)]
555pub struct PhantomReferentMut<T: ?Sized>(*mut T);
556
557impl<T: ?Sized> AsCppRef<T> for PhantomReferentMut<T> {
558 fn as_cpp_ref(&self) -> CppRef<T> {
559 CppRef::from_ptr(self.0)
560 }
561}
562
563impl<T: ?Sized> AsCppMutRef<T> for PhantomReferentMut<T> {
564 fn as_cpp_mut_ref(&mut self) -> CppMutRef<T> {
565 CppMutRef::from_ptr(self.0)
566 }
567}
568
569#[cfg(all(feature = "arbitrary_self_types", test))]
570mod tests {
571 use super::*;
572
573 struct CppOuter {
574 _a: u32,
575 inner: CppInner,
576 global: *const CppInner,
577 }
578
579 impl CppOuter {
580 fn get_inner_ref<'a>(self: &CppRef<'a, CppOuter>) -> CppRef<'a, CppInner> {
581 // Safety: emulating C++ code for test purposes. This is safe
582 // because we know the data isn't modified during the lifetime of
583 // the returned reference.
584 let self_rust_ref = unsafe { self.as_ref() };
585 CppRef::from_ptr(std::ptr::addr_of!(self_rust_ref.inner))
586 }
587 fn get_global_ref<'a>(self: &CppRef<'a, CppOuter>) -> CppRef<'a, CppInner> {
588 // Safety: emulating C++ code for test purposes. This is safe
589 // because we know the data isn't modified during the lifetime of
590 // the returned reference.
591 let self_rust_ref = unsafe { self.as_ref() };
592 CppRef::from_ptr(self_rust_ref.global)
593 }
594 }
595
596 struct CppInner {
597 b: u32,
598 }
599
600 impl CppInner {
601 fn value_is(self: &CppRef<Self>) -> u32 {
602 // Safety: emulating C++ code for test purposes. This is safe
603 // because we know the data isn't modified during the lifetime of
604 // the returned reference.
605 let self_rust_ref = unsafe { self.as_ref() };
606 self_rust_ref.b
607 }
608 }
609
610 #[test]
611 fn cpp_objects() {
612 let mut global = CppInner { b: 7 };
613 let global_ref_lifetime_phantom;
614 {
615 let outer = CppOuter {
616 _a: 12,
617 inner: CppInner { b: 3 },
618 global: &mut global,
619 };
620 let outer = CppPin::new(outer);
621 let inner_ref = outer.as_cpp_ref().get_inner_ref();
622 assert_eq!(inner_ref.value_is(), 3);
623 global_ref_lifetime_phantom = Some(outer.as_cpp_ref().get_global_ref().lifetime_cast());
624 }
625 let global_ref = global_ref_lifetime_phantom.unwrap();
626 let global_ref = global_ref.as_cpp_ref();
627 assert_eq!(global_ref.value_is(), 7);
628 }
629
630 #[test]
631 fn cpp_pin() {
632 let a = RustThing { _a: 4 };
633 let a = CppPin::new(a);
634 let _ = a.as_cpp_ref();
635 let _ = a.as_cpp_ref();
636 }
Brian Silvermanf3ec38b2022-07-06 20:43:36 -0700637}