diff --git a/Cargo.toml b/Cargo.toml index 31840f444..a4c3a7a19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ rust-version = "1.77" resolver = "2" [features] -arbitrary_self_types_pointers = [] +arbitrary_self_types = [] [dependencies] autocxx-macro = { path="macro", version="0.29.0" } diff --git a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs index f73ae0792..ac461bab0 100644 --- a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs +++ b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs @@ -172,9 +172,12 @@ impl TypeConversionPolicy { _ => panic!("Not a pointer"), }; let (ty, wrapper_name) = if is_mut { - (parse_quote! { autocxx::CppMutRef<'a, #ty> }, "CppMutRef") + ( + parse_quote! { autocxx::CppMutLtRef<'a, #ty> }, + "CppMutLtRef", + ) } else { - (parse_quote! { autocxx::CppRef<'a, #ty> }, "CppRef") + (parse_quote! { autocxx::CppLtRef<'a, #ty> }, "CppLtRef") }; let wrapper_name = make_ident(wrapper_name); RustParamConversion::Param { @@ -194,9 +197,9 @@ impl TypeConversionPolicy { _ => panic!("Not a pointer"), }; let ty = if is_mut { - parse_quote! { &mut autocxx::CppMutRef<'a, #ty> } + parse_quote! { autocxx::CppMutRef<#ty> } } else { - parse_quote! { &autocxx::CppRef<'a, #ty> } + parse_quote! { autocxx::CppRef<#ty> } }; RustParamConversion::Param { ty, diff --git a/examples/reference-wrappers/src/main.rs b/examples/reference-wrappers/src/main.rs index 91998fe5c..ca3e0cdc3 100644 --- a/examples/reference-wrappers/src/main.rs +++ b/examples/reference-wrappers/src/main.rs @@ -25,7 +25,7 @@ // Necessary to be able to call methods on reference wrappers. // For that reason, this example only builds on nightly Rust. -#![feature(arbitrary_self_types_pointers)] +#![feature(arbitrary_self_types)] use autocxx::prelude::*; use std::pin::Pin; diff --git a/integration-tests/tests/cpprefs_test.rs b/integration-tests/tests/cpprefs_test.rs index 46349ed7b..902a4c856 100644 --- a/integration-tests/tests/cpprefs_test.rs +++ b/integration-tests/tests/cpprefs_test.rs @@ -27,7 +27,7 @@ fn run_cpprefs_test( generate_pods: &[&str], ) { if !arbitrary_self_types_supported() { - // "unsafe_references_wrapped" requires arbitrary_self_types_pointers, which requires nightly. + // "unsafe_references_wrapped" requires arbitrary_self_types, which requires nightly. return; } do_run_test( @@ -127,7 +127,7 @@ fn test_return_reference_cpprefs() { let rs = quote! { let b = CppPin::new(ffi::Bob { a: 3, b: 4 }); let b_ref = b.as_cpp_ref(); - let bob = ffi::give_bob(&b_ref); + let bob = ffi::give_bob(b_ref); let val = unsafe { bob.as_ref() }; assert_eq!(val.b, 4); }; diff --git a/src/lib.rs b/src/lib.rs index b0eeec17a..eb5623b4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![doc = include_str!("../README.md")] #![cfg_attr(nightly, feature(unsize))] #![cfg_attr(nightly, feature(dispatch_from_dyn))] +#![cfg_attr(nightly, feature(arbitrary_self_types))] // Copyright 2020 Google LLC // @@ -21,7 +22,9 @@ mod rvalue_param; pub mod subclass; mod value_param; -pub use reference_wrapper::{AsCppMutRef, AsCppRef, CppMutRef, CppPin, CppRef, CppUniquePtrPin}; +pub use reference_wrapper::{ + AsCppMutRef, AsCppRef, CppLtRef, CppMutLtRef, CppMutRef, CppPin, CppRef, CppUniquePtrPin, +}; #[cfg_attr(doc, aquamarine::aquamarine)] /// Include some C++ headers in your Rust project. @@ -270,7 +273,7 @@ macro_rules! concrete { /// them to be wrapped in a `CppRef` type: see [`CppRef`]. /// This only works on nightly Rust because it /// depends upon an unstable feature -/// (`arbitrary_self_types_pointers`). However, it should +/// (`arbitrary_self_types`). However, it should /// eliminate all undefined behavior related to Rust's /// stricter aliasing rules than C++. #[macro_export] @@ -594,10 +597,7 @@ pub trait WithinBox { fn within_box(self) -> Pin>; /// Create this item inside a [`CppPin`]. This is a good option if you /// want to own this option within Rust, but you want to create [`CppRef`] - /// C++ references to it. You'd only want to choose that option if you have - /// enabled the C++ reference wrapper support by using the - /// `safety!(unsafe_references_wrapped`) directive. If you haven't done - /// that, ignore this function. + /// C++ references to it. fn within_cpp_pin(self) -> CppPin; } diff --git a/src/reference_wrapper.rs b/src/reference_wrapper.rs index 3d7d560ce..2baeaaa87 100644 --- a/src/reference_wrapper.rs +++ b/src/reference_wrapper.rs @@ -8,8 +8,9 @@ use core::{marker::PhantomData, ops::Deref, pin::Pin}; +use std::ops::DerefMut; #[cfg(nightly)] -use std::{marker::Unsize, ops::DispatchFromDyn}; +use std::{marker::Unsize, ops::DispatchFromDyn, ops::Receiver}; use cxx::{memory::UniquePtrTarget, UniquePtr}; @@ -36,25 +37,15 @@ use cxx::{memory::UniquePtrTarget, UniquePtr}; /// # Calling methods /// /// As noted, one of the main reasons for this type is to call methods. -/// Unfortunately, that depends on unstable Rust features. If you can't +/// Currently, that depends on unstable Rust features. If you can't /// call methods on one of these references, check you're using nightly -/// and add `#![feature(arbitrary_self_types_pointers)]` to your crate. +/// and add `#![feature(arbitrary_self_types)]` to your crate. /// -/// # Lifetimes and cloneability +/// # Lifetimes /// -/// Although these references implement C++ aliasing semantics, they -/// do attempt to give you Rust lifetime tracking. This means if a C++ object -/// gives you a reference, you won't be able to use that reference after the -/// C++ object is no longer around. -/// -/// This is usually what you need, since a C++ object will typically give -/// you a reference to part of _itself_ or something that it owns. But, -/// if you know that the returned reference lasts longer than its vendor, -/// you can use `lifetime_cast` to get a long-lived version. -/// -/// On the other hand, these references do not give you Rust's exclusivity -/// guarantees. These references can be freely cloned, and using [`CppRef::const_cast`] -/// you can even make a mutable reference from an immutable reference. +/// A `CppRef` is not associated with any Rust lifetime. Normally, for +/// ergonomics, you actually may want a lifetime associated. +/// [`CppLtRef`] gives you this. /// /// # Field access /// @@ -68,14 +59,6 @@ use cxx::{memory::UniquePtrTarget, UniquePtr}; /// store a [`CppPin`] in a struct field, get a `CppRef` to its referent, then /// use a setter to reset that field of the struct.) /// -/// # Deref -/// -/// This type implements [`Deref`] because that's the mechanism that the -/// unstable Rust `arbitrary_self_types` features uses to determine callable -/// methods. However, actually calling `Deref::deref` is not permitted and will -/// result in a compilation failure. If you wish to create a Rust reference -/// from the C++ reference, see [`CppRef::as_ref`]. -/// /// # Nullness /// /// Creation of a null C++ reference is undefined behavior (because such @@ -114,15 +97,12 @@ use cxx::{memory::UniquePtrTarget, UniquePtr}; /// Internally, this is represented as a raw pointer in Rust. See the note above /// about Nullness for why we don't use [`core::ptr::NonNull`]. #[repr(transparent)] -pub struct CppRef<'a, T: ?Sized> { - ptr: *const T, - phantom: PhantomData<&'a T>, -} +pub struct CppRef(*const T); -impl<'a, T: ?Sized> CppRef<'a, T> { +impl CppRef { /// Retrieve the underlying C++ pointer. pub fn as_ptr(&self) -> *const T { - self.ptr + self.0 } /// Get a regular Rust reference out of this C++ reference. @@ -142,10 +122,7 @@ impl<'a, T: ?Sized> CppRef<'a, T> { /// Create a C++ reference from a raw pointer. pub fn from_ptr(ptr: *const T) -> Self { - Self { - ptr, - phantom: PhantomData, - } + Self(ptr) } /// Create a mutable version of this reference, roughly equivalent @@ -159,13 +136,56 @@ impl<'a, T: ?Sized> CppRef<'a, T> { /// Because we never dereference a `CppRef` in Rust, this cannot create /// undefined behavior _within Rust_ and is therefore not unsafe. It is /// however generally unwise, just as it is in C++. Use sparingly. - pub fn const_cast(&self) -> CppMutRef<'a, T> { - CppMutRef { - ptr: self.ptr as *mut T, - phantom: PhantomData, + pub fn const_cast(&self) -> CppMutRef { + CppMutRef(self.0 as *mut T) + } +} + +#[cfg(nightly)] +impl Receiver for CppRef { + type Target = T; +} + +impl Clone for CppRef { + fn clone(&self) -> Self { + Self(self.0) + } +} + +impl Copy for CppRef {} + +#[cfg(nightly)] +impl, U: ?Sized> DispatchFromDyn> for CppRef {} + +/// A [`CppRef`] with an associated lifetime. This can be used in place of +/// any `CppRef` due to a `Deref` implementation. +#[repr(transparent)] +pub struct CppLtRef<'a, T: ?Sized> { + ptr: CppRef, + phantom: PhantomData<&'a T>, +} + +impl Deref for CppLtRef<'_, T> { + type Target = CppRef; + fn deref(&self) -> &Self::Target { + // Safety: this type is transparent and contains a CppRef as + // its only non-zero field. + unsafe { std::mem::transmute(self) } + } +} + +impl Clone for CppLtRef<'_, T> { + fn clone(&self) -> Self { + Self { + ptr: self.ptr.clone(), + phantom: self.phantom, } } +} +impl Copy for CppLtRef<'_, T> {} + +impl CppLtRef<'_, T> { /// Extend the lifetime of the returned reference beyond normal Rust /// borrow checker rules. /// @@ -177,49 +197,27 @@ impl<'a, T: ?Sized> CppRef<'a, T> { /// # Usage /// /// When you're given a C++ reference and you know its referent is valid - /// for a long time, use this method. Store the resulting `PhantomReferent` + /// for a long time, use this method. Store the resulting `CppRef` /// somewhere in Rust with an equivalent lifetime. - /// That object can then vend longer-lived `CppRef`s using - /// [`AsCppRef::as_cpp_ref`]. /// /// # Safety /// /// Because `CppRef`s are never dereferenced in Rust, misuse of this API /// cannot lead to undefined behavior _in Rust_ and is therefore not /// unsafe. Nevertheless this can lead to UB in C++, so use carefully. - pub fn lifetime_cast(&self) -> PhantomReferent { - PhantomReferent(self.ptr) - } -} - -impl Deref for CppRef<'_, T> { - type Target = *const T; - #[inline] - fn deref(&self) -> &Self::Target { - // With `inline_const` we can simplify this to: - // const { panic!("you shouldn't deref CppRef!") } - struct C(T); - impl C { - const V: core::convert::Infallible = panic!( - "You cannot directly obtain a Rust reference from a CppRef. Use CppRef::as_ref." - ); - } - match C::::V {} + pub fn lifetime_cast(&self) -> CppRef { + CppRef(self.ptr.as_ptr()) } -} -impl Clone for CppRef<'_, T> { - fn clone(&self) -> Self { + /// Create a C++ reference from a raw pointer. + pub fn from_ptr(ptr: *const T) -> Self { Self { - ptr: self.ptr, - phantom: self.phantom, + ptr: CppRef::from_ptr(ptr), + phantom: PhantomData, } } } -#[cfg(nightly)] -impl, U: ?Sized> DispatchFromDyn> for CppRef<'_, T> {} - /// A C++ non-const reference. These are different from Rust's `&mut T` in that /// several C++ references can exist to the same underlying data ("aliasing") /// and that's not permitted for regular Rust references. @@ -228,15 +226,12 @@ impl, U: ?Sized> DispatchFromDyn> for CppRef /// /// You can convert this to a [`CppRef`] using the [`std::convert::Into`] trait. #[repr(transparent)] -pub struct CppMutRef<'a, T: ?Sized> { - ptr: *mut T, - phantom: PhantomData<&'a mut T>, -} +pub struct CppMutRef(*mut T); -impl CppMutRef<'_, T> { +impl CppMutRef { /// Retrieve the underlying C++ pointer. pub fn as_mut_ptr(&self) -> *mut T { - self.ptr + self.0 } /// Get a regular Rust mutable reference out of this C++ reference. @@ -256,53 +251,60 @@ impl CppMutRef<'_, T> { /// Create a C++ reference from a raw pointer. pub fn from_ptr(ptr: *mut T) -> Self { - Self { - ptr, - phantom: PhantomData, - } - } - - /// Extend the lifetime of the returned reference beyond normal Rust - /// borrow checker rules. See [`CppRef::lifetime_cast`]. - pub fn lifetime_cast(&mut self) -> PhantomReferentMut { - PhantomReferentMut(self.ptr) + Self(ptr) } } -impl Deref for CppMutRef<'_, T> { - type Target = *const T; +/// We implement `Deref` for `CppMutRef` so that any non-mutable +/// methods can be called on a `CppMutRef` instance. +impl Deref for CppMutRef { + type Target = CppRef; #[inline] fn deref(&self) -> &Self::Target { - // With `inline_const` we can simplify this to: - // const { panic!("you shouldn't deref CppRef!") } - struct C(T); - impl C { - const V: core::convert::Infallible = panic!("You cannot directly obtain a Rust reference from a CppMutRef. Use CppMutRef::as_mut."); - } - match C::::V {} + // Safety: `CppMutRef` and `CppRef` have the same + // layout. + unsafe { std::mem::transmute(self) } } } -impl Clone for CppMutRef<'_, T> { +impl Clone for CppMutRef { fn clone(&self) -> Self { - Self { - ptr: self.ptr, - phantom: self.phantom, - } + Self(self.0) + } +} + +impl Copy for CppMutRef {} + +impl From> for CppRef { + fn from(mutable: CppMutRef) -> Self { + Self(mutable.0) } } -impl<'a, T> From> for CppRef<'a, T> { - fn from(mutable: CppMutRef<'a, T>) -> Self { +#[repr(transparent)] +pub struct CppMutLtRef<'a, T: ?Sized> { + ptr: CppMutRef, + phantom: PhantomData<&'a mut T>, +} + +impl CppMutLtRef<'_, T> { + /// Extend the lifetime of the returned reference beyond normal Rust + /// borrow checker rules. See [`CppLtRef::lifetime_cast`]. + pub fn lifetime_cast(&mut self) -> CppMutRef { + CppMutRef(self.ptr.as_mut_ptr()) + } + + /// Create a C++ reference from a raw pointer. + pub fn from_ptr(ptr: *mut T) -> Self { Self { - ptr: mutable.ptr, + ptr: CppMutRef::from_ptr(ptr), phantom: PhantomData, } } } #[cfg(nightly)] -impl, U: ?Sized> DispatchFromDyn> for CppMutRef<'_, T> {} +impl, U: ?Sized> DispatchFromDyn> for CppMutRef {} /// Any type which can return a C++ reference to its contents. pub trait AsCppRef { @@ -316,9 +318,9 @@ pub trait AsCppMutRef: AsCppRef { fn as_cpp_mut_ref(&mut self) -> CppMutRef; } -impl AsCppRef for CppMutRef<'_, T> { +impl AsCppRef for CppMutRef { fn as_cpp_ref(&self) -> CppRef { - CppRef::from_ptr(self.ptr) + CppRef::from_ptr(self.0 as *const T) } } @@ -384,7 +386,9 @@ impl CppPinContents { /// /// See also [`CppUniquePtrPin`], which is equivalent for data which is in /// a [`cxx::UniquePtr`]. -pub struct CppPin(Box>); +// We also keep a `CppMutRef` to the contents for the sake of our `Deref` +// implementation. +pub struct CppPin(Box>, CppMutRef); impl CppPin { /// Imprison the Rust data within a `CppPin`. This eliminates any remaining @@ -395,7 +399,9 @@ impl CppPin { where T: Sized, { - Self(Box::new(CppPinContents(item))) + let mut contents = Box::new(CppPinContents(item)); + let ptr = contents.addr_of_mut(); + Self(contents, CppMutRef(ptr)) } /// Imprison the boxed Rust data within a `CppPin`. This eliminates any remaining @@ -412,8 +418,9 @@ impl CppPin { // to // Box> // is safe. - let contents = unsafe { std::mem::transmute::, Box>>(item) }; - Self(contents) + let mut contents = unsafe { std::mem::transmute::, Box>>(item) }; + let ptr = contents.addr_of_mut(); + Self(contents, CppMutRef(ptr)) } // Imprison the boxed Rust data within a `CppPin`. This eliminates any remaining @@ -493,6 +500,20 @@ impl AsCppMutRef for CppPin { } } +impl Deref for CppPin { + type Target = CppMutRef; + + fn deref(&self) -> &Self::Target { + &self.1 + } +} + +impl DerefMut for CppPin { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.1 + } +} + /// Any newtype wrapper which causes the contained [`UniquePtr`] target to obey C++ reference /// semantics rather than Rust reference semantics. That is, multiple aliasing /// mutable C++ references may exist to the contents. @@ -500,14 +521,15 @@ impl AsCppMutRef for CppPin { /// C++ references are permitted to alias one another, and commonly do. /// Rust references must alias according only to the narrow rules of the /// borrow checker. -pub struct CppUniquePtrPin(UniquePtr); +pub struct CppUniquePtrPin(UniquePtr, CppMutRef); impl CppUniquePtrPin { /// Imprison the type within a `CppPin`. This eliminates any remaining /// Rust references (since we take the item by value) and this object /// subsequently only vends C++ style references, not Rust references. pub fn new(item: UniquePtr) -> Self { - Self(item) + let ptr = item.as_mut_ptr(); + Self(item, CppMutRef::from_ptr(ptr)) } /// Get an immutable pointer to the underlying object. @@ -527,46 +549,26 @@ impl AsCppRef for CppUniquePtrPin { impl AsCppMutRef for CppUniquePtrPin { fn as_cpp_mut_ref(&mut self) -> CppMutRef { - let pinnned_ref: Pin<&mut T> = self - .0 - .as_mut() - .expect("UniquePtr was null; we can't make a C++ reference"); - let ptr = unsafe { Pin::into_inner_unchecked(pinnned_ref) }; - CppMutRef::from_ptr(ptr) + self.1.clone() } } -/// A structure used to extend the lifetime of a returned C++ reference, -/// to indicate to Rust that it's beyond the normal Rust lifetime rules. -/// See [`CppRef::lifetime_cast`]. -#[repr(transparent)] -pub struct PhantomReferent(*const T); +impl Deref for CppUniquePtrPin { + type Target = CppMutRef; -impl AsCppRef for PhantomReferent { - fn as_cpp_ref(&self) -> CppRef { - CppRef::from_ptr(self.0) + fn deref(&self) -> &Self::Target { + &self.1 } } -/// A structure used to extend the lifetime of a returned C++ mutable reference, -/// to indicate to Rust that it's beyond the normal Rust lifetime rules. -/// See [`CppRef::lifetime_cast`]. -#[repr(transparent)] -pub struct PhantomReferentMut(*mut T); - -impl AsCppRef for PhantomReferentMut { +// It would be very nice to be able to impl Deref for UniquePtr +impl AsCppRef for cxx::UniquePtr { fn as_cpp_ref(&self) -> CppRef { - CppRef::from_ptr(self.0) - } -} - -impl AsCppMutRef for PhantomReferentMut { - fn as_cpp_mut_ref(&mut self) -> CppMutRef { - CppMutRef::from_ptr(self.0) + CppRef::from_ptr(self.as_ptr()) } } -#[cfg(all(feature = "arbitrary_self_types_pointers", test))] +#[cfg(all(feature = "arbitrary_self_types", test))] mod tests { use super::*; diff --git a/src/value_param.rs b/src/value_param.rs index 7386d19fb..bb837f11c 100644 --- a/src/value_param.rs +++ b/src/value_param.rs @@ -109,6 +109,8 @@ where } } +// TODO implement for CppPin and for CppRef + unsafe impl ValueParam for UniquePtr where T: UniquePtrTarget,