Skip to main content

autocxx_idalib/
reference_wrapper.rs

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