diff --git a/physx-sys/pxbind/src/consumer.rs b/physx-sys/pxbind/src/consumer.rs index d39291f7..9a9b6c72 100644 --- a/physx-sys/pxbind/src/consumer.rs +++ b/physx-sys/pxbind/src/consumer.rs @@ -729,6 +729,8 @@ pub enum Builtin { // on the C++ side, `void*`, but we want to be able to pack arbitrary data into the space // available so we treat it as a separate type so we can do that properly in the Rust side UserData, + // same as above but `const void* + ConstUserData, } impl Builtin { @@ -761,7 +763,8 @@ impl Builtin { Self::Mat34V => "glam::Affine3A", Self::Mat34 => "Affine", Self::Mat44V | Self::Mat44 => "PxMat44", - Self::UserData => "UserDataField", + Self::UserData => "UserData", + Self::ConstUserData => "ConstUserData", } } @@ -798,6 +801,7 @@ impl Builtin { Self::Mat44V => "physx_Mat44V_Pod", Self::Mat44 => "physx_PxMat44_Pod", Self::UserData => "void*", + Self::ConstUserData => "const void*", } } @@ -834,6 +838,7 @@ impl Builtin { Self::Mat44V => "physx::PxMat44V", Self::Mat44 => "physx::PxMat44", Self::UserData => "void*", + Self::ConstUserData => "const void*", } } diff --git a/physx-sys/pxbind/src/consumer/record.rs b/physx-sys/pxbind/src/consumer/record.rs index 8b410423..d0cddf92 100644 --- a/physx-sys/pxbind/src/consumer/record.rs +++ b/physx-sys/pxbind/src/consumer/record.rs @@ -714,11 +714,15 @@ impl<'ast> super::AstConsumer<'ast> { } let kind = if name == "userData" || name == "mUserData" { - QualType::Builtin(Builtin::UserData) + if kind.qual_type.contains("const") { + QualType::Builtin(Builtin::ConstUserData) + } else { + QualType::Builtin(Builtin::UserData) + } } else { - self - .parse_type(kind, template_types) - .with_context(|| format!("failed to parse type for {rname}::{name}"))? + self.parse_type(kind, template_types).with_context(|| { + format!("failed to parse type for {rname}::{name}") + })? }; // if matches!(&kind, QualType::FunctionPointer) { @@ -727,7 +731,6 @@ impl<'ast> super::AstConsumer<'ast> { let is_reference = matches!(kind, QualType::Reference { .. }); - fields.push(FieldBinding { name, kind, diff --git a/physx-sys/pxbind/tests/snapshots/structgen__all_the_things-3.snap b/physx-sys/pxbind/tests/snapshots/structgen__all_the_things-3.snap index 39d0336a..1d24648f 100644 --- a/physx-sys/pxbind/tests/snapshots/structgen__all_the_things-3.snap +++ b/physx-sys/pxbind/tests/snapshots/structgen__all_the_things-3.snap @@ -563,13 +563,13 @@ pub struct PxSimulationTetrahedronMeshData { #[repr(C)] pub struct PxActor { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxAggregate { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -894,31 +894,31 @@ pub struct PxArticulationTendonLimit { #[repr(C)] pub struct PxArticulationAttachment { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxArticulationTendonJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxArticulationTendon { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxArticulationSpatialTendon { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxArticulationFixedTendon { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -971,31 +971,31 @@ pub struct PxArticulationCache { #[repr(C)] pub struct PxArticulationSensor { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxArticulationReducedCoordinate { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxArticulationJointReducedCoordinate { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxShape { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxRigidActor { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1006,13 +1006,13 @@ pub struct PxNodeIndex { #[repr(C)] pub struct PxRigidBody { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxArticulationLink { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1041,7 +1041,7 @@ pub struct PxConstraintShaderTable { #[repr(C)] pub struct PxConstraint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1150,13 +1150,13 @@ pub struct PxContactModifyPair { #[repr(C)] pub struct PxBaseMaterial { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxFEMMaterial { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1176,7 +1176,7 @@ pub struct PxParticleRigidFilterPair { #[repr(C)] pub struct PxMaterial { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1220,7 +1220,7 @@ pub struct PxParticleSpring { #[repr(C)] pub struct PxParticleMaterial { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1349,13 +1349,13 @@ pub struct PxQueryFilterData { #[repr(C)] pub struct PxRigidDynamic { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxRigidStatic { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1500,7 +1500,7 @@ pub struct PxSceneDesc { pub flags: PxSceneFlags, pub cpuDispatcher: *mut PxCpuDispatcher, pub structgen_pad2: [u8; 8], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, pub solverBatchSize: u32, pub solverArticulationBatchSize: u32, pub nbContactDataBlocks: u32, @@ -1604,7 +1604,7 @@ pub struct PxDominanceGroupPair { #[repr(C)] pub struct PxScene { pub structgen_pad0: [u8; 8], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1827,7 +1827,7 @@ pub struct PxControllerObstacleHit { pub dir: PxVec3, pub length: f32, pub structgen_pad0: [u8; 4], - pub userData: *const std::ffi::c_void, + pub userData: ConstUserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -1861,7 +1861,7 @@ pub struct PxControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, pub structgen_pad4: [u8; 8], } #[derive(Clone, Copy)] @@ -1887,7 +1887,7 @@ pub struct PxBoxControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, pub structgen_pad4: [u8; 4], pub halfHeight: f32, pub halfSideExtent: f32, @@ -1916,7 +1916,7 @@ pub struct PxCapsuleControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, pub structgen_pad4: [u8; 4], pub radius: f32, pub height: f32, @@ -2046,7 +2046,7 @@ pub struct PxDefaultFileInputData { #[repr(C)] pub struct PxJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -2058,7 +2058,7 @@ pub struct PxSpring { #[repr(C)] pub struct PxDistanceJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -2072,13 +2072,13 @@ pub struct PxJacobianRow { #[repr(C)] pub struct PxContactJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxFixedJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -2149,19 +2149,19 @@ pub struct PxJointLimitPyramid { #[repr(C)] pub struct PxPrismaticJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxRevoluteJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxSphericalJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] @@ -2175,19 +2175,19 @@ pub struct PxD6JointDrive { #[repr(C)] pub struct PxD6Joint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxGearJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] pub struct PxRackAndPinionJoint { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[derive(Clone, Copy)] #[repr(C)] diff --git a/physx-sys/pxbind/tests/snapshots/structgen__many_things-3.snap b/physx-sys/pxbind/tests/snapshots/structgen__many_things-3.snap index 19407a2b..24b75971 100644 --- a/physx-sys/pxbind/tests/snapshots/structgen__many_things-3.snap +++ b/physx-sys/pxbind/tests/snapshots/structgen__many_things-3.snap @@ -274,7 +274,7 @@ pub struct PxGeometryHolder { #[repr(C)] pub struct PxShape { pub structgen_pad0: [u8; 16], - pub userData: *mut std::ffi::c_void, + pub userData: UserData, } #[cfg(test)] mod sizes { diff --git a/physx-sys/src/generated/unix/structgen.rs b/physx-sys/src/generated/unix/structgen.rs index 3b2af626..9719a7c1 100644 --- a/physx-sys/src/generated/unix/structgen.rs +++ b/physx-sys/src/generated/unix/structgen.rs @@ -653,14 +653,14 @@ pub struct PxSimulationTetrahedronMeshData { #[repr(C)] pub struct PxActor { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxAggregate { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1007,35 +1007,35 @@ pub struct PxArticulationTendonLimit { #[repr(C)] pub struct PxArticulationAttachment { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationTendonJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationTendon { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationSpatialTendon { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationFixedTendon { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1093,35 +1093,35 @@ pub struct PxArticulationCache { #[repr(C)] pub struct PxArticulationSensor { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationReducedCoordinate { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationJointReducedCoordinate { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxShape { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxRigidActor { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1134,14 +1134,14 @@ pub struct PxNodeIndex { #[repr(C)] pub struct PxRigidBody { pub structgen_pad0: [u8; 16], - pub userData: UserDataField + pub userData: UserData } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationLink { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1174,7 +1174,7 @@ pub struct PxConstraintShaderTable { #[repr(C)] pub struct PxConstraint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1293,14 +1293,14 @@ pub struct PxContactModifyPair { #[repr(C)] pub struct PxBaseMaterial { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxFEMMaterial { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1323,7 +1323,7 @@ pub struct PxParticleRigidFilterPair { #[repr(C)] pub struct PxMaterial { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1372,7 +1372,7 @@ pub struct PxParticleSpring { #[repr(C)] pub struct PxParticleMaterial { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1514,14 +1514,14 @@ pub struct PxQueryFilterData { #[repr(C)] pub struct PxRigidDynamic { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxRigidStatic { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1542,7 +1542,7 @@ pub struct PxSceneQueryDesc { #[repr(C)] pub struct PxBroadPhaseRegion { pub mBounds: PxBounds3, - pub mUserData: UserDataField, + pub mUserData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1677,7 +1677,7 @@ pub struct PxSceneDesc { pub flags: PxSceneFlags, pub cpuDispatcher: *mut PxCpuDispatcher, pub structgen_pad2: [u8; 8], - pub userData: UserDataField, + pub userData: UserData, pub solverBatchSize: u32, pub solverArticulationBatchSize: u32, pub nbContactDataBlocks: u32, @@ -1787,7 +1787,7 @@ pub struct PxDominanceGroupPair { #[repr(C)] pub struct PxScene { pub structgen_pad0: [u8; 8], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1936,7 +1936,7 @@ pub struct PxExtendedVec3 { #[repr(C)] pub struct PxObstacle { pub structgen_pad0: [u8; 8], - pub mUserData: UserDataField, + pub mUserData: UserData, pub mPos: PxExtendedVec3, pub mRot: PxQuat, } @@ -1945,7 +1945,7 @@ pub struct PxObstacle { #[repr(C)] pub struct PxBoxObstacle { pub structgen_pad0: [u8; 8], - pub mUserData: UserDataField, + pub mUserData: UserData, pub mPos: PxExtendedVec3, pub mRot: PxQuat, pub mHalfExtents: PxVec3, @@ -1956,7 +1956,7 @@ pub struct PxBoxObstacle { #[repr(C)] pub struct PxCapsuleObstacle { pub structgen_pad0: [u8; 8], - pub mUserData: UserDataField, + pub mUserData: UserData, pub mPos: PxExtendedVec3, pub mRot: PxQuat, pub mHalfHeight: f32, @@ -2034,7 +2034,7 @@ pub struct PxControllerObstacleHit { pub dir: PxVec3, pub length: f32, pub structgen_pad0: [u8; 4], - pub userData: *const std::ffi::c_void, + pub userData: ConstUserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2070,7 +2070,7 @@ pub struct PxControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: UserDataField, + pub userData: UserData, pub structgen_pad4: [u8; 8], } #[derive(Clone, Copy)] @@ -2097,7 +2097,7 @@ pub struct PxBoxControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: UserDataField, + pub userData: UserData, pub structgen_pad4: [u8; 4], pub halfHeight: f32, pub halfSideExtent: f32, @@ -2127,7 +2127,7 @@ pub struct PxCapsuleControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: UserDataField, + pub userData: UserData, pub structgen_pad4: [u8; 4], pub radius: f32, pub height: f32, @@ -2272,7 +2272,7 @@ pub struct PxDefaultFileInputData { #[repr(C)] pub struct PxJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2286,7 +2286,7 @@ pub struct PxSpring { #[repr(C)] pub struct PxDistanceJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2302,14 +2302,14 @@ pub struct PxJacobianRow { #[repr(C)] pub struct PxContactJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxFixedJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2387,21 +2387,21 @@ pub struct PxJointLimitPyramid { #[repr(C)] pub struct PxPrismaticJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxRevoluteJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxSphericalJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2417,21 +2417,21 @@ pub struct PxD6JointDrive { #[repr(C)] pub struct PxD6Joint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxGearJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxRackAndPinionJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] diff --git a/physx-sys/src/generated/x86_64-pc-windows-msvc/structgen.rs b/physx-sys/src/generated/x86_64-pc-windows-msvc/structgen.rs index 8596b3b7..7405f613 100644 --- a/physx-sys/src/generated/x86_64-pc-windows-msvc/structgen.rs +++ b/physx-sys/src/generated/x86_64-pc-windows-msvc/structgen.rs @@ -653,14 +653,14 @@ pub struct PxSimulationTetrahedronMeshData { #[repr(C)] pub struct PxActor { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxAggregate { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1012,35 +1012,35 @@ pub struct PxArticulationTendonLimit { #[repr(C)] pub struct PxArticulationAttachment { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationTendonJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationTendon { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationSpatialTendon { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationFixedTendon { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1098,35 +1098,35 @@ pub struct PxArticulationCache { #[repr(C)] pub struct PxArticulationSensor { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationReducedCoordinate { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationJointReducedCoordinate { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxShape { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxRigidActor { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1139,14 +1139,14 @@ pub struct PxNodeIndex { #[repr(C)] pub struct PxRigidBody { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxArticulationLink { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1179,7 +1179,7 @@ pub struct PxConstraintShaderTable { #[repr(C)] pub struct PxConstraint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1298,14 +1298,14 @@ pub struct PxContactModifyPair { #[repr(C)] pub struct PxBaseMaterial { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxFEMMaterial { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1328,7 +1328,7 @@ pub struct PxParticleRigidFilterPair { #[repr(C)] pub struct PxMaterial { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1377,7 +1377,7 @@ pub struct PxParticleSpring { #[repr(C)] pub struct PxParticleMaterial { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1519,14 +1519,14 @@ pub struct PxQueryFilterData { #[repr(C)] pub struct PxRigidDynamic { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxRigidStatic { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1547,7 +1547,7 @@ pub struct PxSceneQueryDesc { #[repr(C)] pub struct PxBroadPhaseRegion { pub mBounds: PxBounds3, - pub mUserData: UserDataField, + pub mUserData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1682,7 +1682,7 @@ pub struct PxSceneDesc { pub flags: PxSceneFlags, pub cpuDispatcher: *mut PxCpuDispatcher, pub structgen_pad2: [u8; 8], - pub userData: UserDataField, + pub userData: UserData, pub solverBatchSize: u32, pub solverArticulationBatchSize: u32, pub nbContactDataBlocks: u32, @@ -1792,7 +1792,7 @@ pub struct PxDominanceGroupPair { #[repr(C)] pub struct PxScene { pub structgen_pad0: [u8; 8], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -1941,7 +1941,7 @@ pub struct PxExtendedVec3 { #[repr(C)] pub struct PxObstacle { pub structgen_pad0: [u8; 8], - pub mUserData: UserDataField, + pub mUserData: UserData, pub mPos: PxExtendedVec3, pub mRot: PxQuat, } @@ -1950,7 +1950,7 @@ pub struct PxObstacle { #[repr(C)] pub struct PxBoxObstacle { pub structgen_pad0: [u8; 8], - pub mUserData: UserDataField, + pub mUserData: UserData, pub mPos: PxExtendedVec3, pub mRot: PxQuat, pub mHalfExtents: PxVec3, @@ -1961,7 +1961,7 @@ pub struct PxBoxObstacle { #[repr(C)] pub struct PxCapsuleObstacle { pub structgen_pad0: [u8; 8], - pub mUserData: UserDataField, + pub mUserData: UserData, pub mPos: PxExtendedVec3, pub mRot: PxQuat, pub mHalfHeight: f32, @@ -2039,7 +2039,7 @@ pub struct PxControllerObstacleHit { pub dir: PxVec3, pub length: f32, pub structgen_pad0: [u8; 4], - pub userData: *const std::ffi::c_void, + pub userData: ConstUserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2075,7 +2075,7 @@ pub struct PxControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: UserDataField, + pub userData: UserData, pub structgen_pad4: [u8; 8], } #[derive(Clone, Copy)] @@ -2102,7 +2102,7 @@ pub struct PxBoxControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: UserDataField, + pub userData: UserData, pub structgen_pad4: [u8; 8], pub halfHeight: f32, pub halfSideExtent: f32, @@ -2133,7 +2133,7 @@ pub struct PxCapsuleControllerDesc { pub registerDeletionListener: bool, pub clientID: u8, pub structgen_pad3: [u8; 6], - pub userData: UserDataField, + pub userData: UserData, pub structgen_pad4: [u8; 8], pub radius: f32, pub height: f32, @@ -2279,7 +2279,7 @@ pub struct PxDefaultFileInputData { #[repr(C)] pub struct PxJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2293,7 +2293,7 @@ pub struct PxSpring { #[repr(C)] pub struct PxDistanceJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2309,14 +2309,14 @@ pub struct PxJacobianRow { #[repr(C)] pub struct PxContactJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxFixedJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2394,21 +2394,21 @@ pub struct PxJointLimitPyramid { #[repr(C)] pub struct PxPrismaticJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxRevoluteJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxSphericalJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] @@ -2424,21 +2424,21 @@ pub struct PxD6JointDrive { #[repr(C)] pub struct PxD6Joint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxGearJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] #[repr(C)] pub struct PxRackAndPinionJoint { pub structgen_pad0: [u8; 16], - pub userData: UserDataField, + pub userData: UserData, } #[derive(Clone, Copy)] #[cfg_attr(feature = "debug-structs", derive(Debug))] diff --git a/physx-sys/src/lib.rs b/physx-sys/src/lib.rs index 4f9465f7..e04f123c 100644 --- a/physx-sys/src/lib.rs +++ b/physx-sys/src/lib.rs @@ -197,48 +197,133 @@ pub const fn version(major: u32, minor: u32, patch: u32) -> u32 { } const fn can_pack_into_pointer() -> bool { - core::mem::size_of::() <= core::mem::size_of::<*mut c_void>() && core::mem::align_of::() <= core::mem::align_of::<*mut c_void>() + core::mem::size_of::() <= core::mem::size_of::<*mut c_void>() + && core::mem::align_of::() <= core::mem::align_of::<*mut c_void>() } -/// The type of `userData` fields, which is a `void*` pointer in the PhysX api, but which -/// we turn into this `union` on the Rust side to be able to pack small user data types inline into -/// the space of the pointer itself when possible. -// -// NOTE: In a world where cross-language C-to-Rust link-time optimization existed and we statically -// linked PhysX, this could possibly break since on the PhsyX side it's a `void*` which is -// `noundef` under Clang whereas we explicitly allow types with arbitrary layout (including -// padding) to be packed as long as they have the necessary size an alignment. But, cross-lang -// LTO like that does not currently exist and is unlikely to happen, so it's probably Fine TM. +/// The type of `const void* userData` parameters in functions. Only allows shared access to the +/// underlying data. Modification is still possible for data on the heap by using internal +/// mutability. +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct ConstUserData(UserData); + +impl ConstUserData { + /// Get a reference to previously-initialized data of type `T`. + /// + /// # Safety + /// + /// You must have previously initialized `self` by calling `new_maybe_packed` or `intialize_maybe_packed` with + /// data of the same exact `T` on the `UserData` that this came from, and not have already + /// called `drop_and_dealloc` on `self` since doing so. + #[inline(always)] + pub unsafe fn maybe_packed_data_ref(&self) -> &T { + self.0.maybe_packed_data_ref::() + } + + /// Get a reference to previously-initialized data of type `T` which you know was initialized + /// on the heap (i.e. through `new_on_heap` or `initialize_on_heap`). + /// + /// # Safety + /// + /// You must have previously initialized `self` by calling `new_on_heap` or `initialize_on_heap` + /// with data of the same exact `T` on the `UserData` that this came from, and not have already + /// called `heap_drop_and_dealloc` on `self` since doing so. + #[inline(always)] + pub unsafe fn heap_data_ref(&self) -> &T { + self.0.heap_data_ref::() + } +} + +/// The type of `void* userData` fields and function parameters, which is a `void*` pointer in the +/// PhysX api, but which we turn into this `union` on the Rust side to be able to pack small user +/// data types inline into the space of the pointer itself when possible. +/// +/// In a given situation, you should choose whether you want to exploit the idea of trying to pack +/// data into the size of the pointer or not. If so, use the `maybe_packed` family of methods. +/// If not, use the `heap` family of methods. +/// +/// NOTE: In a world where cross-language C-to-Rust link-time optimization existed and we statically +/// linked PhysX, this could possibly break since on the PhsyX side it's a `void*` which is +/// `noundef` under Clang whereas we explicitly allow types with arbitrary layout (including +/// padding) to be packed as long as they have the necessary size an alignment. But, cross-lang +/// LTO like that does not currently exist and is unlikely to happen, so it's Fine TM. #[repr(C)] #[derive(Clone, Copy)] -#[cfg_attr(feature = "debug-structs", derive(Debug))] -pub union UserDataField { +pub union UserData { heap_pointer: *mut c_void, packed_data: MaybeUninit<*mut c_void>, } -impl Default for UserDataField { +impl Default for UserData { #[inline(always)] fn default() -> Self { - Self::new_uninit() + Self::null() } } -impl UserDataField { - /// Create a new `UserDataField` which is immediately initialized with the given `data`. See - /// [`UserDataField::initialize_with_data`] for more details. - pub fn new_with_data(data: T) -> Self { - let mut ret = Self::new_uninit(); - ret.initialize_with_data(data); +impl UserData { + /// Create a new `UserData` which is immediately initialized with the given `data`. + /// + /// See [`UserData::initialize_maybe_packed`] for more details. + #[inline] + pub fn new_maybe_packed(data: T) -> Self { + let mut ret = UserData { + packed_data: MaybeUninit::uninit(), + }; + ret.initialize_maybe_packed(data); + ret + } + + /// Create a new `UserData` by placing `data` of type `T` on the heap and then making `self` + /// a pointer to that data. + /// + /// See [`UserData::initialize_on_heap`] for more information. + #[inline] + pub fn new_on_heap(data: T) -> Self { + let mut ret = UserData { + packed_data: MaybeUninit::uninit(), + }; + ret.initialize_on_heap(data); ret } - /// Create a new `UserDataField` which is uninitialized. Initialized it before use! + /// Create a new `UserData` which is zeroed, i.e. a null pointer. You still must + /// initialize it before using any of the data accessor methods! #[inline(always)] - pub fn new_uninit() -> Self { - UserDataField { packed_data: MaybeUninit::uninit() } + pub fn null() -> Self { + UserData { + heap_pointer: core::ptr::null_mut(), + } + } + + /// Returns true if `T` would be packed when using the maybe-packed initialization methods + /// on `UserData` + #[inline(always)] + pub const fn can_pack() -> bool { + can_pack_into_pointer::() + } + /// Initialize the field by placing `data` of type `T` on the heap and then making `self` + /// a pointer to that data. + /// + /// This is useful in cases where a `user_data` will be passed back through a callback function + /// and you want to be able to guarantee you can modify the actual stored user data. In such + /// cases, if we packed the data into the `void*` pointer, that data is passed by-value into + /// our callback function and so any modifications that happen to it inline wouldn't actually + /// be written back to where the data is stored in memory. + /// + /// In order to access it, you should use `heap_data_ref`, `heap_data_mut`, and dealloc/drop + /// it with `heap_drop_and_dealloc`. This is because if `T`'s layout can fit within the + /// size of a pointer, the regular `data_ref`, `data_mut`, and `drop_and_dealloc` functions + /// will assume `self` has been initialized as packed data, which would result in + /// undefined behavior when `self` (which is a pointer) is interpreted as a `T`. + #[inline(always)] + pub fn initialize_on_heap(&mut self, data: T) { + let heap_ptr = Box::into_raw(Box::new(data)); + self.heap_pointer = heap_ptr.cast(); } + /// Initialize the field with arbitrary user data of type `T`. /// /// If the data can be packed into the space of a `*mut c_void` (its size and alignement are @@ -248,14 +333,14 @@ impl UserDataField { /// /// You can access data you've initialized using the other functions available on this type. /// If `T` could not be packed and was put on the heap, you must call - /// [`UserDataField::drop_and_dealloc`] with the same `T` in order to drop and deallocate it, + /// [`UserData::drop_and_dealloc`] with the same `T` in order to drop and deallocate it, /// if you care about it being dropped or dealloced (if not, the memory will leak). /// /// If you call this when data has already been initialized, it will be clobbered if /// it was written inline and if it was on the heap the old data will be leaked and replaced /// with the new data. #[inline] - pub fn initialize_with_data(&mut self, data: T) { + pub fn initialize_maybe_packed(&mut self, data: T) { if can_pack_into_pointer::() { // SAFETY: We've checked T's size and align are both < *mut c_void, which `self` must // be at least size/align of @@ -263,8 +348,7 @@ impl UserDataField { core::ptr::write(core::ptr::addr_of_mut!(self.packed_data).cast::(), data); } } else { - let heap_ptr = Box::into_raw(Box::new(data)); - self.heap_pointer = heap_ptr.cast(); + self.initialize_on_heap::(data); } } @@ -272,42 +356,97 @@ impl UserDataField { /// /// # Safety /// - /// You must have previously initialized `self` by calling `initialize_with_data` with data - /// of the same exact `T`, and not have already called `drop_and_dealloc` on `self` since + /// You must have previously initialized `self` by calling `new_maybe_packed` or `initialize_maybe_packed` with + /// data of the same exact `T`, and not have already called `drop_and_dealloc` on `self` since /// doing so. #[inline(always)] - pub unsafe fn data_ref(&self) -> &T { + pub unsafe fn maybe_packed_data_ref(&self) -> &T { if can_pack_into_pointer::() { // SAFETY: if function level safety is true, we must have initialized a valid T inside - // self as packed, since we use the same check in `initialize_with_data` + // self as packed, since we use the same check in `auto_initialize_with_data` unsafe { &*(core::ptr::addr_of!(self.packed_data).cast::()) } } else { // SAFETY: if function level safety is true, we must have initialized a valid T on - // the heap which we point to, since we use the same check in `initialize_with_data` - unsafe { &*(self.heap_pointer.cast::().cast_const()) } + // the heap which we point to, since we use the same check in `auto_initialize_with_data` + self.heap_data_ref::() } } + /// Get a reference to previously-initialized data of type `T` which you know was initialized + /// on the heap (i.e. through `new_on_heap` or `initialize_on_heap`). + /// + /// Note that the lifetime of the returned reference is scoped to the borrow of `self`, which is + /// the most conservative estimate of its lifetime. However, in some cases this is overly + /// restrictive. In that case you can either use `&mut *slf.as_mut_ptr()` and deref or + /// `transmute` the returned reference from this function to extend the lifetime if you know + /// doing so is valid. + /// + /// # Safety + /// + /// You must have previously initialized `self` by calling `new_on_heap` or `initialize_on_heap` + /// with data of the same exact `T` on the `UserData` that this came from, and not have already + /// called `heap_drop_and_dealloc` on `self` since doing so. + #[inline(always)] + pub unsafe fn heap_data_ref(&self) -> &T { + unsafe { &*(self.heap_pointer.cast::().cast_const()) } + } + /// Get a reference to previously-initialized data of type `T`. /// /// # Safety /// - /// You must have previously initialized `self` by calling `initialize_with_data` with data - /// of the same exact `T`, and not have already called `drop_and_dealloc` on `self` since + /// You must have previously initialized `self` by calling `new_maybe_packed` or `initialize_maybe_packed` with + /// data of the same exact `T`, and not have already called `drop_and_dealloc` on `self` since /// doing so. #[inline(always)] - pub unsafe fn data_ref_mut(&mut self) -> &mut T { + pub unsafe fn maybe_packed_data_mut(&mut self) -> &mut T { if can_pack_into_pointer::() { // SAFETY: if function level safety is true, we must have initialized a valid T inside - // self as packed, since we use the same check in `initialize_with_data` + // self as packed, since we use the same check in `initialize_maybe_packed` unsafe { &mut *(core::ptr::addr_of_mut!(self.packed_data).cast::()) } } else { // SAFETY: if function level safety is true, we must have initialized a valid T on - // the heap which we point to, since we use the same check in `initialize_with_data` - unsafe { &mut *(self.heap_pointer.cast::()) } + // the heap which we point to, since we use the same check in `initialize_maybe_packed` + self.heap_data_mut::() } } + /// Get a reference to previously-initialized data of type `T` which you know was initialized + /// on the heap (i.e. through `new_on_heap` or `initialize_on_heap`). + /// + /// Note that the lifetime of the returned reference is scoped to the borrow of `self`, which is + /// the most conservative estimate of its lifetime. However, in some cases this is overly + /// restrictive. In that case you can either use `&mut *slf.as_mut_ptr()` and deref or + /// `transmute` the returned reference from this function to extend the lifetime if you know + /// doing so is valid. + /// + /// # Safety + /// + /// You must have previously initialized `self` by calling `new_on_heap` or `initialize_on_heap` + /// with data of the same exact `T` on the `UserData` that this came from, and not have already + /// called `heap_drop_and_dealloc` on `self` since doing so. + #[inline(always)] + pub unsafe fn heap_data_mut(&mut self) -> &mut T { + unsafe { &mut *(self.heap_pointer.cast::()) } + } + + /// Drop and deallocate the space that was allocated for the data on the heap. + /// + /// # Safety + /// + /// You must have previously initialized `self` by calling `new_on_heap` or `initialize_on_heap` + /// with data of the same exact `T`, and not have already called `drop_and_dealloc` on `self` + /// since doing so. + #[inline] + pub unsafe fn heap_drop_and_dealloc(&mut self) { + // SAFETY: self is a heap_pointer and must have been initialized due to function safety + let ptr = unsafe { self.heap_pointer }.cast::(); + // SAFETY: we must have constructed the value pointed to by `ptr` by putting it in a box + // if the function level safety is met. + let reconsructed_box = unsafe { Box::from_raw(ptr) }; + drop(reconsructed_box); + } + /// Drop and deallocate the space that was allocated for the data on the heap, if there was /// any. /// @@ -316,74 +455,95 @@ impl UserDataField { /// /// # Safety /// - /// You must have previously initialized `self` by calling `initialize_with_data` with data - /// of the same exact `T`, and not have already called `drop_and_dealloc` on `self` since + /// You must have previously initialized `self` by calling `new_maybe_packed` or `initialize_maybe_packed` with + /// data of the same exact `T`, and not have already called `drop_and_dealloc` on `self` since /// doing so. - #[inline] - pub unsafe fn drop_and_dealloc(&mut self) { - if !can_pack_into_pointer::() { - // SAFETY: self is a heap_pointer and must have been initialized due to function safety - let ptr = unsafe { self.heap_pointer }.cast::(); + #[inline(always)] + pub unsafe fn maybe_packed_drop_and_dealloc(&mut self) { + if can_pack_into_pointer::() { + // SAFETY: self is a packed T and has not been dropped according to function safety + // and the fact we use the same check in `initialize_maybe_packed` + unsafe { core::ptr::drop_in_place(self.maybe_packed_data_mut::()) } + } else { // SAFETY: we must have constructed the value pointed to by `ptr` by putting it in a box // if the function level safety is met. - let reconsructed_box = unsafe { Box::from_raw(ptr) }; - drop(reconsructed_box); - } else { - unsafe { - core::ptr::drop_in_place(self.data_ref_mut::()) - } + unsafe { self.heap_drop_and_dealloc::() } } } + + /// Interpret `self` as a `*mut T` + /// + /// # Safety + /// + /// `self` must have been previously initialized as a pointer, i.e. through one of the + /// heap initialization functions or [`UserData::null`]. It **must not** contain any + /// uninit bytes, i.e. [`UserData::uninit`] or writing a `T` that is not a pointer packed + /// into `self` + #[inline(always)] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + self.heap_pointer.cast::() + } + + /// Interpret `self` as a `*const T` + /// + /// # Safety + /// + /// `self` must have been previously initialized as a pointer, i.e. through one of the + /// heap initialization functions or [`UserData::null`]. It **must not** contain any + /// uninit bytes, i.e. [`UserData::uninit`] or writing a `T` that is not a pointer packed + /// into `self` + #[inline(always)] + pub unsafe fn as_ptr(&self) -> *const T { + self.heap_pointer.cast::().cast_const() + } + + /// Interpret `self` as a `*const c_void` and check if it is null. + /// + /// # Safety + /// + /// `self` must have been previously initialized as a pointer, i.e. through one of the + /// heap initialization functions or [`UserData::null`]. It **must not** contain any + /// uninit bytes, i.e. [`UserData::uninit`] or writing a `T` that is not a pointer packed + /// into `self` + #[inline(always)] + pub unsafe fn is_null(&self) -> bool { + self.as_ptr::().is_null() + } } + pub type CollisionCallback = - unsafe extern "C" fn(*mut c_void, *const PxContactPairHeader, *const PxContactPair, u32); + unsafe extern "C" fn(UserData, *const PxContactPairHeader, *const PxContactPair, u32); -pub type TriggerCallback = unsafe extern "C" fn(*mut c_void, *const PxTriggerPair, u32); +pub type TriggerCallback = unsafe extern "C" fn(UserData, *const PxTriggerPair, u32); -pub type ConstraintBreakCallback = unsafe extern "C" fn(*mut c_void, *const PxConstraintInfo, u32); +pub type ConstraintBreakCallback = unsafe extern "C" fn(UserData, *const PxConstraintInfo, u32); -pub type WakeSleepCallback = unsafe extern "C" fn(*mut c_void, *const *const PxActor, u32, bool); +pub type WakeSleepCallback = unsafe extern "C" fn(UserData, *const *const PxActor, u32, bool); pub type AdvanceCallback = - unsafe extern "C" fn(*mut c_void, *const *const PxRigidBody, *const PxTransform, u32); + unsafe extern "C" fn(UserData, *const *const PxRigidBody, *const PxTransform, u32); // Function pointers in Rust are normally not nullable (which is why they don't require unsafe to call) // but we need them to be, so we simply wrap them in Option<>. An Option is luckily represented // by the compiler as a simple pointer with null representing None, so this is compatible with the C struct. #[repr(C)] +#[derive(Default)] pub struct SimulationEventCallbackInfo { // Callback for collision events. pub collision_callback: Option, - pub collision_user_data: *mut c_void, + pub collision_user_data: UserData, // Callback for trigger shape events (an object entered or left a trigger shape). pub trigger_callback: Option, - pub trigger_user_data: *mut c_void, + pub trigger_user_data: UserData, // Callback for when a constraint breaks (such as a joint with a force limit) pub constraint_break_callback: Option, - pub constraint_break_user_data: *mut c_void, + pub constraint_break_user_data: UserData, // Callback for when an object falls asleep or is awoken. pub wake_sleep_callback: Option, - pub wake_sleep_user_data: *mut c_void, + pub wake_sleep_user_data: UserData, // Callback to get the next pose early for objects (if flagged with eENABLE_POSE_INTEGRATION_PREVIEW). pub advance_callback: Option, - pub advance_user_data: *mut c_void, -} - -impl Default for SimulationEventCallbackInfo { - fn default() -> Self { - Self { - collision_callback: None, - collision_user_data: std::ptr::null_mut(), - trigger_callback: None, - trigger_user_data: std::ptr::null_mut(), - constraint_break_callback: None, - constraint_break_user_data: std::ptr::null_mut(), - wake_sleep_callback: None, - wake_sleep_user_data: std::ptr::null_mut(), - advance_callback: None, - advance_user_data: std::ptr::null_mut(), - } - } + pub advance_user_data: UserData, } pub type RaycastHitCallback = unsafe extern "C" fn( @@ -391,11 +551,11 @@ pub type RaycastHitCallback = unsafe extern "C" fn( *const PxFilterData, *const PxShape, hit_flags: u32, - *const c_void, + ConstUserData, ) -> PxQueryHitType; pub type PostFilterCallback = - unsafe extern "C" fn(*const PxFilterData, *const PxQueryHit, *const c_void) -> PxQueryHitType; + unsafe extern "C" fn(*const PxFilterData, *const PxQueryHit, ConstUserData) -> PxQueryHitType; #[repr(C)] pub struct FilterShaderCallbackInfo { @@ -412,28 +572,28 @@ pub type SimulationFilterShader = unsafe extern "C" fn(*mut FilterShaderCallbackInfo) -> PxFilterFlags; pub type RaycastProcessTouchesCallback = - unsafe extern "C" fn(*const PxRaycastHit, u32, *mut c_void) -> bool; + unsafe extern "C" fn(*const PxRaycastHit, u32, UserData) -> bool; pub type SweepProcessTouchesCallback = - unsafe extern "C" fn(*const PxSweepHit, u32, *mut c_void) -> bool; + unsafe extern "C" fn(*const PxSweepHit, u32, UserData) -> bool; pub type OverlapProcessTouchesCallback = - unsafe extern "C" fn(*const PxOverlapHit, u32, *mut c_void) -> bool; + unsafe extern "C" fn(*const PxOverlapHit, u32, UserData) -> bool; -pub type FinalizeQueryCallback = unsafe extern "C" fn(*mut c_void); +pub type FinalizeQueryCallback = unsafe extern "C" fn(UserData); pub type AllocCallback = - unsafe extern "C" fn(u64, *const c_void, *const c_void, u32, *const c_void) -> *mut c_void; + unsafe extern "C" fn(u64, *const c_void, *const c_void, u32, ConstUserData) -> *mut c_void; -pub type DeallocCallback = unsafe extern "C" fn(*const c_void, *const c_void); +pub type DeallocCallback = unsafe extern "C" fn(*const c_void, ConstUserData); pub type ZoneStartCallback = - unsafe extern "C" fn(*const i8, bool, u64, *const c_void) -> *mut c_void; + unsafe extern "C" fn(*const i8, bool, u64, ConstUserData) -> *mut c_void; -pub type ZoneEndCallback = unsafe extern "C" fn(*const c_void, *const i8, bool, u64, *const c_void); +pub type ZoneEndCallback = unsafe extern "C" fn(*const c_void, *const i8, bool, u64, ConstUserData); pub type ErrorCallback = - unsafe extern "C" fn(PxErrorCode, *const i8, *const i8, u32, *const c_void); + unsafe extern "C" fn(PxErrorCode, *const i8, *const i8, u32, ConstUserData); -pub type AssertHandler = unsafe extern "C" fn(*const i8, *const i8, u32, *mut bool, *const c_void); +pub type AssertHandler = unsafe extern "C" fn(*const i8, *const i8, u32, *mut bool, ConstUserData); extern "C" { pub fn physx_create_foundation() -> *mut PxFoundation; @@ -472,21 +632,21 @@ extern "C" { finalize_query_callback: FinalizeQueryCallback, touches_buffer: *mut PxRaycastHit, num_touches: u32, - userdata: *mut c_void, + userdata: UserData, ) -> *mut PxRaycastCallback; pub fn create_sweep_callback( process_touches_callback: SweepProcessTouchesCallback, finalize_query_callback: FinalizeQueryCallback, touches_buffer: *mut PxSweepHit, num_touches: u32, - userdata: *mut c_void, + userdata: UserData, ) -> *mut PxSweepCallback; pub fn create_overlap_callback( process_touches_callback: OverlapProcessTouchesCallback, finalize_query_callback: FinalizeQueryCallback, touches_buffer: *mut PxOverlapHit, num_touches: u32, - userdata: *mut c_void, + userdata: UserData, ) -> *mut PxOverlapCallback; pub fn delete_raycast_callback(callback: *mut PxRaycastCallback); @@ -496,25 +656,25 @@ extern "C" { pub fn create_alloc_callback( alloc_callback: AllocCallback, dealloc_callback: DeallocCallback, - userdata: *mut c_void, + userdata: UserData, ) -> *mut PxAllocatorCallback; pub fn create_profiler_callback( zone_start_callback: ZoneStartCallback, zone_end_callback: ZoneEndCallback, - userdata: *mut c_void, + userdata: UserData, ) -> *mut PxProfilerCallback; - pub fn get_alloc_callback_user_data(alloc_callback: *mut PxAllocatorCallback) -> *mut c_void; + pub fn get_alloc_callback_user_data(alloc_callback: *mut PxAllocatorCallback) -> UserData; pub fn create_error_callback( error_callback: ErrorCallback, - userdata: *mut c_void, + userdata: UserData, ) -> *mut PxErrorCallback; pub fn create_assert_handler( error_callback: AssertHandler, - userdata: *mut c_void, + userdata: UserData, ) -> *mut PxAssertHandler; pub fn get_default_simulation_filter_shader() -> *mut c_void; @@ -524,8 +684,9 @@ extern "C" { #[deprecated] pub fn create_contact_callback( callback: CollisionCallback, - userdata: *mut c_void, + userdata: UserData, ) -> *mut PxSimulationEventCallback; + /// Deallocates the PxSimulationEventCallback that has previously been created #[deprecated()] pub fn destroy_contact_callback(callback: *mut PxSimulationEventCallback); diff --git a/physx-sys/src/physx_generated.rs b/physx-sys/src/physx_generated.rs index cfc45d47..fc977a54 100644 --- a/physx-sys/src/physx_generated.rs +++ b/physx-sys/src/physx_generated.rs @@ -9099,7 +9099,7 @@ extern "C" { /// be referenced by other objects or the simulation might still be running and accessing the object state. In such cases the destructor will be called /// as soon as it is safe to do so. After the destruction of the object and its memory, an eMEMORY_RELEASE event will get fired. In this case it is not /// allowed to dereference the object pointer in the callback. - pub fn PxDeletionListener_onRelease_mut(self_: *mut PxDeletionListener, observed: *const PxBase, userData: *mut std::ffi::c_void, deletionEvent: PxDeletionEventFlag); + pub fn PxDeletionListener_onRelease_mut(self_: *mut PxDeletionListener, observed: *const PxBase, userData: UserData, deletionEvent: PxDeletionEventFlag); pub fn PxBaseMaterial_isKindOf(self_: *const PxBaseMaterial, name: *const std::ffi::c_char) -> bool; @@ -11818,10 +11818,10 @@ extern "C" { /// Returns the user data associated with this controller. /// /// The user pointer associated with the controller. - pub fn PxController_getUserData(self_: *const PxController) -> *mut std::ffi::c_void; + pub fn PxController_getUserData(self_: *const PxController) -> UserData; /// Sets the user data associated with this controller. - pub fn PxController_setUserData_mut(self_: *mut PxController, userData: *mut std::ffi::c_void); + pub fn PxController_setUserData_mut(self_: *mut PxController, userData: UserData); /// Returns information about the controller's internal state. pub fn PxController_getState(self_: *const PxController, state: *mut PxControllerState); diff --git a/physx/examples/profiler.rs b/physx/examples/profiler.rs index d19e4626..860dfb37 100644 --- a/physx/examples/profiler.rs +++ b/physx/examples/profiler.rs @@ -1,4 +1,5 @@ use physx::{physics::ProfilerCallback, prelude::*}; +use physx_sys::ConstUserData; use std::ffi::CStr; type PxMaterial = physx::material::PxMaterial<()>; @@ -72,9 +73,9 @@ unsafe impl ProfilerCallback for PrintProfilerCallback { _name: *const i8, _detached: bool, _context_id: u64, - user_data: *const std::ffi::c_void, + user_data: ConstUserData, ) -> *mut std::ffi::c_void { - let this = &*user_data.cast::(); + let this = user_data.heap_data_ref::(); let start = this.start.elapsed().as_micros() as u64; start as *mut std::ffi::c_void @@ -85,10 +86,10 @@ unsafe impl ProfilerCallback for PrintProfilerCallback { name: *const i8, _detached: bool, _context_id: u64, - user_data: *const std::ffi::c_void, + user_data: ConstUserData, ) { let name: &'static str = std::mem::transmute(CStr::from_ptr(name).to_str().unwrap()); - let this = &*user_data.cast::(); + let this = user_data.heap_data_ref::(); let end = this.start.elapsed().as_micros() as u64; let start = context as u64; diff --git a/physx/src/articulation_link.rs b/physx/src/articulation_link.rs index cfd40450..6a0757c7 100644 --- a/physx/src/articulation_link.rs +++ b/physx/src/articulation_link.rs @@ -7,12 +7,12 @@ use crate::{ rigid_actor::RigidActor, rigid_body::RigidBody, shape::{Shape, ShapeFlag}, - traits::{Class, UserData}, + traits::{Class, HasUserData}, }; use std::marker::PhantomData; -use physx_sys::UserDataField; +use physx_sys::UserData; #[rustfmt::skip] use physx_sys::{ PxArticulationLink_getChildren, @@ -31,16 +31,16 @@ pub struct PxArticulationLink { phantom_user_data: PhantomData<(L, Geom)>, } -unsafe impl UserData for PxArticulationLink { +impl HasUserData for PxArticulationLink { type UserData = L; #[inline] - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } #[inline] - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } } @@ -78,7 +78,7 @@ impl RigidActor for PxArticulationLink { impl ArticulationLink for PxArticulationLink {} -pub trait ArticulationLink: Class + RigidBody + UserData { +pub trait ArticulationLink: Class + RigidBody + HasUserData { /// # Safety /// /// Owner's own the pointer they wrap, using the pointer after dropping the Owner, @@ -96,14 +96,14 @@ pub trait ArticulationLink: Class + RigidBody + U #[inline] fn get_user_data(&self) -> &Self::UserData { // Safety: all construction goes through from_raw, which calls init_user_data - unsafe { UserData::get_user_data(self) } + unsafe { HasUserData::get_user_data(self) } } /// Get the user data. #[inline] fn get_user_data_mut(&mut self) -> &mut Self::UserData { // Safety: all construction goes through from_raw, which calls init_user_data - unsafe { UserData::get_user_data_mut(self) } + unsafe { HasUserData::get_user_data_mut(self) } } /// Enable collisions for this link. Equivalent to setting SimulationShape to false for all attached shapes. diff --git a/physx/src/articulation_reduced_coordinate.rs b/physx/src/articulation_reduced_coordinate.rs index f655f753..d13c556d 100644 --- a/physx/src/articulation_reduced_coordinate.rs +++ b/physx/src/articulation_reduced_coordinate.rs @@ -10,12 +10,12 @@ use super::{ owner::Owner, rigid_actor::RigidActor, shape::CollisionLayers, - traits::{Class, UserData}, + traits::{Class, HasUserData}, }; use std::{marker::PhantomData, ptr::drop_in_place}; -use physx_sys::UserDataField; +use physx_sys::UserData; #[rustfmt::skip] use physx_sys::{ PxArticulationReducedCoordinate_applyCache_mut, @@ -66,14 +66,14 @@ pub struct PxArticulationReducedCoordinate { phantom_user_data: PhantomData<(U, Link)>, } -unsafe impl UserData for PxArticulationReducedCoordinate { +impl HasUserData for PxArticulationReducedCoordinate { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } } @@ -120,7 +120,7 @@ impl ArticulationReducedCoordinate } pub trait ArticulationReducedCoordinate: - Class + UserData + Class + HasUserData { type ArticulationLink: ArticulationLink; @@ -143,13 +143,13 @@ pub trait ArticulationReducedCoordinate: /// Get a reference to the user data. fn get_user_data(&self) -> &Self::UserData { // Safety: construction must go through `from_raw` which calls `init_user_data` - unsafe { UserData::get_user_data(self) } + unsafe { HasUserData::get_user_data(self) } } /// Get a mutable reference to the user data. fn get_user_data_mut(&mut self) -> &mut Self::UserData { // Safety: construction must go through `from_raw` which calls `init_user_data` - unsafe { UserData::get_user_data_mut(self) } + unsafe { HasUserData::get_user_data_mut(self) } } #[inline] diff --git a/physx/src/controller.rs b/physx/src/controller.rs index dc613f73..43a100cb 100644 --- a/physx/src/controller.rs +++ b/physx/src/controller.rs @@ -4,12 +4,12 @@ use crate::{ material::Material, math::{PxExtendedVec3, PxVec3}, owner::Owner, - traits::{Class, UserData}, + traits::{Class, HasUserData}, }; -use std::{ffi::c_void, marker::PhantomData, mem::size_of, ptr::drop_in_place}; +use std::marker::PhantomData; -use physx_sys::UserDataField; +use physx_sys::UserData; use thiserror::Error; #[rustfmt::skip] @@ -46,41 +46,49 @@ pub trait Controller: Class + Sized { type UserData; type Descriptor: Class; - /// Retrieve the user data from the controller. - // Due to the size trick employed and the API decision to expose this userData via method calls, - // get_user_data_mut will not work for small sizes of U, since getUserData returns a copy of the field, - // rather than being able to write a method that returns a pointer to the field or the field itself. - fn get_user_data(&self) -> &Self::UserData { - unsafe { - if size_of::() > size_of::<*mut c_void>() { - // Cast *mut c_void to appropriate type and reborrow - &*(PxController_getUserData(self.as_ptr()) as *const Self::UserData) - } else { - // DATA_SIZE < VOID_SIZE - // The data is packed into the "*mut c_void" - &*(&PxController_getUserData(self.as_ptr()) as *const *mut c_void - as *const Self::UserData) - } - } + /// Sets the controller's user data. + fn set_user_data(&mut self, user_data: Self::UserData) -> &mut Self { + let user_data = UserData::new_maybe_packed(user_data); + // SAFETY: self is not null and is Class user_data is valid + unsafe { PxController_setUserData_mut(self.as_mut_ptr(), user_data) } + self } - /// Sets the controllers user data. If U is larger than a *mut _, it is heap allocated in a box. - /// Otherwise, it is packed directly into the *mut c_void userData field. - fn set_user_data(&mut self, user_data: Self::UserData) -> &mut Self { - unsafe { - let user_data: *mut c_void = if size_of::() > size_of::<*mut c_void>() { - // Allocate on heap since it is too large to pack into *mut c_void field - let user_data = Box::new(user_data); - // Cast to *mut c_void - Box::into_raw(user_data) as *mut c_void - } else { - // DATA_SIZE < VOID_SIZE - // The data is small enough to be packed directly into the "*mut c_void" - *(&user_data as *const Self::UserData as *const *mut c_void) - }; - PxController_setUserData_mut(self.as_mut_ptr(), user_data); + /// Retrieve the user data from the controller. Must have been already created with + /// `set_user_data` or will return `None` + fn get_user_data(&self) -> Option<&Self::UserData> { + // SAFETY: self is a valid reference and is Class + let user_data = unsafe { PxController_getUserData(self.as_ptr()) }; + // SAFETY: we only ever init the user data as a pointer, so if it's nonnull we know we have + // valid data, and it will live on the heap at least as long as we have a borrow of self + // since it only will go out of scope by being able to have a mut ref to self + unsafe { user_data.as_ptr::().as_ref() } + } + + /// Retrieve a mutable reference to the user data from the controller. Must have been already + /// created with `set_user_data` or will return `None`. + fn get_user_data_mut(&mut self) -> Option<&mut Self::UserData> { + // SAFETY: self is a valid reference and is Class + let mut user_data = unsafe { PxController_getUserData(self.as_ptr()) }; + // SAFETY: we only ever init the user data as a pointer, so if it's nonnull we know we have + // valid data, and it will live on the heap at least as long as we have a borrow of self + // since it only will go out of scope by being able to have a mut ref to self + unsafe { user_data.as_mut_ptr::().as_mut() } + } + + /// If it exists, drop and dealloc associated user data. + fn drop_and_dealloc_user_data(&mut self) { + // SAFETY: self is a valid reference and is Class + let mut user_data = unsafe { PxController_getUserData(self.as_ptr()) }; + // SAFETY: we only initialize user_data as a pointer ever + let is_null = unsafe { user_data.is_null() }; + if !is_null { + // SAFETY: if the user_data is not null, we must have allocated it as on the heap + // and it may be drop and dealloced + unsafe { + user_data.heap_drop_and_dealloc::(); + } } - self } /// Set the position of teh controller @@ -119,13 +127,7 @@ where impl Drop for PxCapsuleController { fn drop(&mut self) { unsafe { - if size_of::() > size_of::<*mut c_void>() { - drop_in_place(PxController_getUserData(self.as_ptr()) as *mut U); - } else { - drop_in_place( - (&mut PxController_getUserData(self.as_ptr())) as *mut *mut c_void as *mut U, - ); - }; + self.drop_and_dealloc_user_data(); PxController_release_mut(self.as_mut_ptr()) } } @@ -234,21 +236,47 @@ impl PxCapsuleControllerDesc { } } -unsafe impl UserData for PxCapsuleControllerDesc { +// override default behavior because we need the `userData` that gets passed along to the +// `Controller` this creates to be on the heap, which expects it to be so (see implementation +// of `Controller` trait) +impl HasUserData for PxCapsuleControllerDesc { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } + + fn init_user_data(&mut self, user_data: Self::UserData) -> &mut Self { + self.user_data_ptr_mut() + .initialize_on_heap::(user_data); + self + } + + unsafe fn drop_and_dealloc_user_data(&mut self) { + // SAFETY: same as function-level safety + unsafe { + self.user_data_ptr_mut() + .heap_drop_and_dealloc::() + } + } + + unsafe fn get_user_data(&self) -> &Self::UserData { + unsafe { self.user_data_ptr().heap_data_ref::() } + } + + unsafe fn get_user_data_mut(&mut self) -> &mut Self::UserData { + unsafe { self.user_data_ptr_mut().heap_data_mut::() } + } } impl Drop for PxCapsuleControllerDesc { fn drop(&mut self) { unsafe { + // SAFETY: we always initialize this in the only public constructors self.drop_and_dealloc_user_data(); PxCapsuleControllerDesc_delete(self.as_mut_ptr()); } @@ -277,13 +305,7 @@ where impl Drop for PxBoxController { fn drop(&mut self) { unsafe { - if size_of::() > size_of::<*mut c_void>() { - drop_in_place(PxController_getUserData(self.as_ptr()) as *mut U); - } else { - drop_in_place( - (&mut PxController_getUserData(self.as_ptr())) as *mut *mut c_void as *mut U, - ); - }; + self.drop_and_dealloc_user_data(); PxController_release_mut(self.as_mut_ptr()) } } @@ -394,21 +416,47 @@ impl PxBoxControllerDesc { } } -unsafe impl UserData for PxBoxControllerDesc { +// override default behavior because we need the `userData` that gets passed along to the +// `Controller` this creates to be on the heap, which expects it to be so (see implementation +// of `Controller` trait) +impl HasUserData for PxBoxControllerDesc { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } + + fn init_user_data(&mut self, user_data: Self::UserData) -> &mut Self { + self.user_data_ptr_mut() + .initialize_on_heap::(user_data); + self + } + + unsafe fn drop_and_dealloc_user_data(&mut self) { + // SAFETY: same as function-level safety + unsafe { + self.user_data_ptr_mut() + .heap_drop_and_dealloc::() + } + } + + unsafe fn get_user_data(&self) -> &Self::UserData { + unsafe { self.user_data_ptr().heap_data_ref::() } + } + + unsafe fn get_user_data_mut(&mut self) -> &mut Self::UserData { + unsafe { self.user_data_ptr_mut().heap_data_mut::() } + } } impl Drop for PxBoxControllerDesc { fn drop(&mut self) { unsafe { + // SAFETY: we always initialize this in the only public constructors self.drop_and_dealloc_user_data(); PxBoxControllerDesc_delete(self.as_mut_ptr()) } diff --git a/physx/src/foundation.rs b/physx/src/foundation.rs index 30fe3e2a..32267b58 100644 --- a/physx/src/foundation.rs +++ b/physx/src/foundation.rs @@ -6,6 +6,7 @@ use crate::{owner::Owner, traits::Class}; +use physx_sys::{ConstUserData, UserData}; #[rustfmt::skip] use physx_sys::{ create_alloc_callback, @@ -152,10 +153,21 @@ pub trait Foundation: Class + Sized { /// Get the allocator callback. fn get_allocator_callback(&mut self) -> Option<&mut Self::Allocator> { - unsafe { - (get_alloc_callback_user_data(PxFoundation_getAllocatorCallback_mut(self.as_mut_ptr())) - as *mut Self::Allocator) - .as_mut() + let px_allocatorcallback = + unsafe { PxFoundation_getAllocatorCallback_mut(self.as_mut_ptr()) }; + if px_allocatorcallback.is_null() { + None + } else { + // SAFETY: we know px_allocatorcallback is not null, and the only way for that to happen when using + // the safe wrapper is if we initialized it properly + let mut userdata = unsafe { get_alloc_callback_user_data(px_allocatorcallback) }; + // SAFETY: if we got a non-null allocatorcallback object back, then we must also have a non-null pointer + // to a `Self::Allocator` in the userdata because we initialize it ourselves in the implementation of `AllocatorCallback`, + // which `Self::Allocator` implements and uses to initialize itself. + // + // we assert the lifetime of `allocator_mut` to be at least as long as the borrow of `self`, which is true since it's on the heap + // and we don't clean it up + Some(unsafe { &mut *userdata.as_mut_ptr::() }) } } @@ -199,8 +211,17 @@ impl ScratchBuffer { /// /// Reporting the name, file and line is not enabled by default. /// Use [`Foundation::set_report_allocation_names`] to toggle this on or off. +/// +/// When you use `AllocatorCallback::into_px(self)`, the `self` you pass in will be +/// placed on the heap and a pointer to it will be passed into the `user_data` in the +/// `allocate` and `deallocate` functions. Keep in mind the threading context you're using and +/// ensure that the type you're implementing this on is sufficiently thread-safe for the kinds +/// of access you are doing. #[allow(clippy::missing_safety_doc)] pub unsafe trait AllocatorCallback: Sized { + /// `user_data` will be a forced-heap-pointer to a `Self`. So you can access the `self` that + /// `into_px` was called on by calling `user_data.heap_data_ref::()`. + /// /// # Safety /// /// Allocations must be aligned 16. This should not panic, since it is @@ -210,13 +231,16 @@ pub unsafe trait AllocatorCallback: Sized { name: *const c_void, file: *const c_void, line: u32, - user_data: *const c_void, + user_data: ConstUserData, ) -> *mut c_void; + /// `user_data` will be a forced-heap-pointer to a `Self`. So you can access the `self` that + /// `into_px` was called on by calling `user_data.heap_data_ref::()`. + /// /// # Safety /// /// Must not panic. - unsafe extern "C" fn deallocate(ptr: *const c_void, user_data: *const c_void); + unsafe extern "C" fn deallocate(ptr: *const c_void, user_data: ConstUserData); /// # Safety /// @@ -226,7 +250,7 @@ pub unsafe trait AllocatorCallback: Sized { create_alloc_callback( Self::allocate, Self::deallocate, - Box::into_raw(Box::new(self)) as *mut c_void, + UserData::new_on_heap(self), ) } } @@ -241,7 +265,7 @@ unsafe impl AllocatorCallback for GlobalAllocCallback { _name: *const c_void, _file: *const c_void, _line: u32, - _user_data: *const c_void, + _user_data: ConstUserData, ) -> *mut c_void { let alloc_size = size as usize + 16; let layout = std::alloc::Layout::from_size_align(alloc_size, 16).unwrap(); @@ -252,7 +276,7 @@ unsafe impl AllocatorCallback for GlobalAllocCallback { } } - unsafe extern "C" fn deallocate(ptr: *const c_void, _user_data: *const c_void) { + unsafe extern "C" fn deallocate(ptr: *const c_void, _user_data: ConstUserData) { let ptr = (ptr as usize - 16) as *mut u64; unsafe { let size = *ptr; @@ -285,12 +309,12 @@ unsafe impl AllocatorCallback for TrackingAllocator { _name: *const c_void, _file: *const c_void, _line: u32, - user_data: *const c_void, + user_data: ConstUserData, ) -> *mut c_void { - let user_data = unsafe { &*(user_data as *const Self) }; let alloc_size = size as usize + 16; let layout = std::alloc::Layout::from_size_align(alloc_size, 16).unwrap(); - user_data.allocated.fetch_add(layout.size(), SeqCst); + let this = unsafe { user_data.heap_data_ref::() }; + this.allocated.fetch_add(layout.size(), SeqCst); unsafe { let allocation = alloc(layout) as *mut u64; *allocation = alloc_size as u64; @@ -298,12 +322,12 @@ unsafe impl AllocatorCallback for TrackingAllocator { } } - unsafe extern "C" fn deallocate(ptr: *const c_void, user_data: *const c_void) { - let user_data = unsafe { &*(user_data as *const Self) }; + unsafe extern "C" fn deallocate(ptr: *const c_void, user_data: ConstUserData) { let ptr = (ptr as usize - 16) as *mut u64; let size = unsafe { *ptr }; let layout = Layout::from_size_align(size as usize, 16).unwrap(); - user_data.deallocated.fetch_add(layout.size(), SeqCst); + let this = unsafe { user_data.heap_data_ref::() }; + this.deallocated.fetch_add(layout.size(), SeqCst); unsafe { dealloc(ptr as *mut u8, layout) } } } @@ -321,12 +345,12 @@ unsafe impl AllocatorCallback for DefaultAllocator { _name: *const c_void, _file: *const c_void, _line: u32, - _user_data: *const c_void, + _user_data: ConstUserData, ) -> *mut c_void { unreachable!() } - unsafe extern "C" fn deallocate(_ptr: *const c_void, _user_data: *const c_void) { + unsafe extern "C" fn deallocate(_ptr: *const c_void, _user_data: ConstUserData) { unreachable!() } } diff --git a/physx/src/material.rs b/physx/src/material.rs index cdce539d..ffeae8b0 100644 --- a/physx/src/material.rs +++ b/physx/src/material.rs @@ -1,11 +1,11 @@ use crate::{ owner::Owner, - traits::{Class, UserData}, + traits::{Class, HasUserData}, }; use std::marker::PhantomData; -use physx_sys::UserDataField; +use physx_sys::UserData; #[rustfmt::skip] use physx_sys::{ PxMaterial_getDynamicFriction, @@ -37,14 +37,14 @@ pub struct PxMaterial { phantom_user_data: PhantomData, } -unsafe impl UserData for PxMaterial { +impl HasUserData for PxMaterial { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } } @@ -75,7 +75,7 @@ unsafe impl Sync for PxMaterial {} impl Material for PxMaterial {} -pub trait Material: Class + UserData { +pub trait Material: Class + HasUserData { /// # Safety /// /// Owner's own the pointer they wrap, using the pointer after dropping the Owner, @@ -92,14 +92,14 @@ pub trait Material: Class + UserData { #[inline] fn get_user_data(&self) -> &Self::UserData { // Safety: all constructors go through from_raw which calls init_user_data - unsafe { UserData::get_user_data(self) } + unsafe { HasUserData::get_user_data(self) } } /// Get a mutable reference to the user data. #[inline] fn get_user_data_mut(&mut self) -> &mut Self::UserData { // Safety: all constructors go through from_raw which calls init_user_data - unsafe { UserData::get_user_data_mut(self) } + unsafe { HasUserData::get_user_data_mut(self) } } /// Set the dynamic friction. diff --git a/physx/src/physics.rs b/physx/src/physics.rs index 9619936b..895087a5 100644 --- a/physx/src/physics.rs +++ b/physx/src/physics.rs @@ -30,7 +30,7 @@ use crate::{ scene::PxScene, shape::{Shape, ShapeFlags}, simulation_event_callback::*, - traits::{Class, Descriptor, SceneDescriptor, UserData}, + traits::{Class, Descriptor, HasUserData, SceneDescriptor}, triangle_mesh::TriangleMesh, visual_debugger::VisualDebugger, }; @@ -394,7 +394,7 @@ pub trait Physics: Class + Sized { static_friction: f32, dynamic_friction: f32, restitution: f32, - user_data: <::Material as UserData>::UserData, + user_data: <::Material as HasUserData>::UserData, ) -> Option::Material>> { unsafe { Material::from_raw( @@ -460,7 +460,7 @@ pub trait Physics: Class + Sized { materials: &mut [&mut ::Material], is_exclusive: bool, shape_flags: ShapeFlags, - user_data: ::UserData, + user_data: ::UserData, ) -> Option> { unsafe { Shape::from_raw( diff --git a/physx/src/physics/assert_handler.rs b/physx/src/physics/assert_handler.rs index 93abf1ef..2fc47d1c 100644 --- a/physx/src/physics/assert_handler.rs +++ b/physx/src/physics/assert_handler.rs @@ -1,6 +1,6 @@ -use std::ffi::{c_void, CStr}; +use std::ffi::CStr; -use physx_sys::{create_assert_handler, PxAssertHandler}; +use physx_sys::{create_assert_handler, ConstUserData, PxAssertHandler, UserData}; /// This represents the (deprecated) PxAssertHandler interface. pub trait AssertHandler: Sized { @@ -18,25 +18,20 @@ pub trait AssertHandler: Sized { file: *const i8, line: u32, should_ignore: *mut bool, - this: *const c_void, + user_data: ConstUserData, ) { unsafe { - let this = &*this.cast::(); let expr = CStr::from_ptr(expr.cast()); let expr = expr.to_string_lossy(); let file = CStr::from_ptr(file.cast()); let file = file.to_string_lossy(); + let this = user_data.heap_data_ref::(); this.on_assert(&expr, &file, line, &mut *should_ignore); } } - unsafe { - create_assert_handler( - on_message_shim::, - Box::into_raw(Box::new(self)) as *mut c_void, - ) - } + unsafe { create_assert_handler(on_message_shim::, UserData::new_on_heap(self)) } } } diff --git a/physx/src/physics/error_callback.rs b/physx/src/physics/error_callback.rs index 2f5229fe..5b58d5d1 100644 --- a/physx/src/physics/error_callback.rs +++ b/physx/src/physics/error_callback.rs @@ -1,5 +1,5 @@ -use physx_sys::{create_error_callback, PxErrorCallback, PxErrorCode}; -use std::ffi::{c_void, CStr}; +use physx_sys::{create_error_callback, ConstUserData, PxErrorCallback, PxErrorCode, UserData}; +use std::ffi::CStr; pub trait ErrorCallback: Sized { fn report_error(&self, code: PxErrorCode, message: &str, file: &str, line: u32); @@ -12,25 +12,20 @@ pub trait ErrorCallback: Sized { message: *const i8, file: *const i8, line: u32, - this: *const c_void, + user_data: ConstUserData, ) { unsafe { - let this = &*this.cast::(); let msg = CStr::from_ptr(message.cast()); let msg = msg.to_string_lossy(); let file = CStr::from_ptr(file.cast()); let file = file.to_string_lossy(); + let this = user_data.heap_data_ref::(); this.report_error(code, &msg, &file, line); } } - unsafe { - create_error_callback( - on_message_shim::, - Box::into_raw(Box::new(self)) as *mut c_void, - ) - } + unsafe { create_error_callback(on_message_shim::, UserData::new_on_heap(self)) } } } diff --git a/physx/src/physics/profiler.rs b/physx/src/physics/profiler.rs index 0d8fce1a..35fce371 100644 --- a/physx/src/physics/profiler.rs +++ b/physx/src/physics/profiler.rs @@ -1,4 +1,4 @@ -use physx_sys::{create_profiler_callback, PxProfilerCallback}; +use physx_sys::{create_profiler_callback, ConstUserData, PxProfilerCallback, UserData}; use std::ffi::c_void; /// A trait for creating profiler callbacks for PhysX. @@ -13,7 +13,7 @@ pub unsafe trait ProfilerCallback: Sized { name: *const i8, detached: bool, context_id: u64, - user_data: *const c_void, + user_data: ConstUserData, ) -> *mut c_void; /// # Safety @@ -25,7 +25,7 @@ pub unsafe trait ProfilerCallback: Sized { name: *const i8, detached: bool, context_id: u64, - user_data: *const c_void, + user_data: ConstUserData, ); /// # Safety @@ -36,7 +36,7 @@ pub unsafe trait ProfilerCallback: Sized { create_profiler_callback( Self::zone_start, Self::zone_end, - Box::into_raw(Box::new(self)) as *mut c_void, + UserData::new_on_heap(self), ) } } diff --git a/physx/src/rigid_dynamic.rs b/physx/src/rigid_dynamic.rs index 87876fd3..75587a29 100644 --- a/physx/src/rigid_dynamic.rs +++ b/physx/src/rigid_dynamic.rs @@ -10,12 +10,12 @@ use crate::{ rigid_actor::RigidActor, rigid_body::RigidBody, shape::Shape, - traits::{Class, UserData}, + traits::{Class, HasUserData}, }; use std::marker::PhantomData; -use physx_sys::UserDataField; +use physx_sys::UserData; #[rustfmt::skip] use physx_sys::{ phys_PxCreateDynamic, @@ -55,14 +55,14 @@ pub struct PxRigidDynamic { phantom_user_data: PhantomData<(D, Geom)>, } -unsafe impl UserData for PxRigidDynamic { +impl HasUserData for PxRigidDynamic { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } } @@ -98,7 +98,7 @@ impl RigidActor for PxRigidDynamic { impl RigidDynamic for PxRigidDynamic {} -pub trait RigidDynamic: Class + RigidBody + UserData { +pub trait RigidDynamic: Class + RigidBody + HasUserData { /// Create a new RigidDynamic. #[inline] fn new( @@ -148,14 +148,14 @@ pub trait RigidDynamic: Class + RigidBody + UserData #[inline] fn get_user_data(&self) -> &Self::UserData { // SAFETY: all construction goes through from_raw, which calls init_user_data - unsafe { UserData::get_user_data(self) } + unsafe { HasUserData::get_user_data(self) } } /// Get the user data. #[inline] fn get_user_data_mut(&mut self) -> &mut Self::UserData { // SAFETY: all construction goes through from_raw, which calls init_user_data - unsafe { UserData::get_user_data_mut(self) } + unsafe { HasUserData::get_user_data_mut(self) } } /// Set the linear velocity. diff --git a/physx/src/rigid_static.rs b/physx/src/rigid_static.rs index d4f9d04b..7f2caa44 100644 --- a/physx/src/rigid_static.rs +++ b/physx/src/rigid_static.rs @@ -11,10 +11,10 @@ use crate::{ physics::Physics, rigid_actor::RigidActor, shape::Shape, - traits::{Class, UserData}, + traits::{Class, HasUserData}, }; -use physx_sys::UserDataField; +use physx_sys::UserData; #[rustfmt::skip] use physx_sys::{ phys_PxCreateStatic, @@ -30,14 +30,14 @@ pub struct PxRigidStatic { phantom_user_data: PhantomData<(S, Geom)>, } -unsafe impl UserData for PxRigidStatic { +impl HasUserData for PxRigidStatic { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } } @@ -73,7 +73,7 @@ impl RigidActor for PxRigidStatic { impl RigidStatic for PxRigidStatic {} -pub trait RigidStatic: Class + RigidActor + UserData { +pub trait RigidStatic: Class + RigidActor + HasUserData { /// Create a new RigidStatic. fn new( physics: &mut impl Physics, @@ -115,13 +115,13 @@ pub trait RigidStatic: Class + RigidActor + UserData { /// Get the user data. fn get_user_data(&self) -> &Self::UserData { // Safety: all construction goes through from_raw, which calls init_user_data - unsafe { UserData::get_user_data(self) } + unsafe { HasUserData::get_user_data(self) } } /// Get the user data. fn get_user_data_mut(&mut self) -> &mut Self::UserData { // Safety: all construction goes through from_raw, which calls init_user_data - unsafe { UserData::get_user_data_mut(self) } + unsafe { HasUserData::get_user_data_mut(self) } } /// Get the name of the real type referenced by this pointer, or None if the returned string is not valid diff --git a/physx/src/scene.rs b/physx/src/scene.rs index 17e6c8ac..c50f76b0 100644 --- a/physx/src/scene.rs +++ b/physx/src/scene.rs @@ -23,7 +23,7 @@ use crate::{ AdvanceCallback, CollisionCallback, ConstraintBreakCallback, PxSimulationEventCallback, TriggerCallback, WakeSleepCallback, }, - traits::{Class, UserData}, + traits::{Class, HasUserData}, visual_debugger::PvdSceneClient, }; @@ -32,7 +32,7 @@ use std::{ ptr::{drop_in_place, null, null_mut}, }; -use physx_sys::UserDataField; +use physx_sys::UserData; // A glob import is super tempting, but the wrappers shadow the names of the physx_sys types, // so those types cannot be in scope. Plus, it easier to see what's been implemented. #[rustfmt::skip] @@ -161,7 +161,7 @@ where phantom_user_data: PhantomData<(U, L, S, D, C, OC, OT, OCB, OWS, OA)>, } -unsafe impl UserData +impl HasUserData for PxScene where L: ArticulationLink, @@ -176,11 +176,11 @@ where { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } } @@ -296,7 +296,7 @@ where type Aggregate = PxAggregate; } -pub trait Scene: Class + UserData { +pub trait Scene: Class + HasUserData { type ArticulationLink: ArticulationLink; type RigidStatic: RigidStatic; type RigidDynamic: RigidDynamic; @@ -316,13 +316,13 @@ pub trait Scene: Class + UserData { /// Get the user data. fn get_user_data(&self) -> &Self::UserData { // Safety: Scenes are constructed from SceneDescriptor which sets up user data appropriately - unsafe { UserData::get_user_data(self) } + unsafe { HasUserData::get_user_data(self) } } /// Get the user data. fn get_user_data_mut(&mut self) -> *mut Self::UserData { // Safety: Scenes are constructed from SceneDescriptor which sets up user data appropriately - unsafe { UserData::get_user_data_mut(self) } + unsafe { HasUserData::get_user_data_mut(self) } } /// Get the visual debugger client diff --git a/physx/src/shape.rs b/physx/src/shape.rs index 536cb71f..0cf384ed 100644 --- a/physx/src/shape.rs +++ b/physx/src/shape.rs @@ -7,12 +7,12 @@ use crate::{ material::Material, owner::Owner, - traits::{Class, UserData}, + traits::{Class, HasUserData}, }; use std::marker::PhantomData; -use physx_sys::UserDataField; +use physx_sys::UserData; #[rustfmt::skip] use physx_sys::{ PxFilterData, @@ -48,14 +48,14 @@ pub struct PxShape { phantom_user_data: PhantomData<(U, M)>, } -unsafe impl UserData for PxShape { +impl HasUserData for PxShape { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.obj.userData } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.obj.userData } } @@ -90,7 +90,7 @@ impl Shape for PxShape { type Material = M; } -pub trait Shape: Class + UserData { +pub trait Shape: Class + HasUserData { type Material: Material; /// # Safety @@ -110,13 +110,13 @@ pub trait Shape: Class + UserData { /// Get a reference to the user data. fn get_user_data(&self) -> &Self::UserData { // Safety: all construction goes through from_raw, which calls init_user_data - unsafe { UserData::get_user_data(self) } + unsafe { HasUserData::get_user_data(self) } } /// Get a mutable reference to the user data. fn get_user_data_mut(&mut self) -> &mut Self::UserData { // Safety: all construction goes through from_raw, which calls init_user_data - unsafe { UserData::get_user_data_mut(self) } + unsafe { HasUserData::get_user_data_mut(self) } } /// Set the simulation (collision) filter of this shape diff --git a/physx/src/simulation_event_callback.rs b/physx/src/simulation_event_callback.rs index dfec8255..09b6440f 100644 --- a/physx/src/simulation_event_callback.rs +++ b/physx/src/simulation_event_callback.rs @@ -1,4 +1,4 @@ -use std::{ffi::c_void, marker::PhantomData, ptr::null_mut, slice}; +use std::{marker::PhantomData, slice}; #[rustfmt::skip] use crate::{ @@ -12,6 +12,7 @@ use crate::{ traits::Class, }; +use physx_sys::UserData; #[rustfmt::skip] use physx_sys::{ create_simulation_event_callbacks, @@ -97,15 +98,15 @@ where { unsafe { let (collision_callback, collision_user_data) = - on_collide.map_or((None, null_mut()), OC::into_cb_user_data); + on_collide.map_or((None, UserData::null()), OC::into_cb_user_data); let (trigger_callback, trigger_user_data) = - on_trigger.map_or((None, null_mut()), OT::into_cb_user_data); + on_trigger.map_or((None, UserData::null()), OT::into_cb_user_data); let (constraint_break_callback, constraint_break_user_data) = - on_constraint_break.map_or((None, null_mut()), OCB::into_cb_user_data); + on_constraint_break.map_or((None, UserData::null()), OCB::into_cb_user_data); let (wake_sleep_callback, wake_sleep_user_data) = - on_wake_sleep.map_or((None, null_mut()), OWS::into_cb_user_data); + on_wake_sleep.map_or((None, UserData::null()), OWS::into_cb_user_data); let (advance_callback, advance_user_data) = - on_advance.map_or((None, null_mut()), OA::into_cb_user_data); + on_advance.map_or((None, UserData::null()), OA::into_cb_user_data); Owner::from_raw( create_simulation_event_callbacks(&SimulationEventCallbackInfo { @@ -142,20 +143,21 @@ where unsafe { let info = &mut *get_simulation_event_info(self.as_mut_ptr()); { - if !info.collision_user_data.is_null() { - drop(Box::from_raw(info.collision_user_data as *mut OC)); + if info.collision_callback.is_some() { + info.collision_user_data.heap_drop_and_dealloc::(); }; - if !info.trigger_user_data.is_null() { - drop(Box::from_raw(info.trigger_user_data as *mut OT)); + if info.trigger_callback.is_some() { + info.trigger_user_data.heap_drop_and_dealloc::(); }; - if !info.constraint_break_user_data.is_null() { - drop(Box::from_raw(info.constraint_break_user_data as *mut OCB)); + if info.constraint_break_callback.is_some() { + info.constraint_break_user_data + .heap_drop_and_dealloc::(); }; - if !info.wake_sleep_user_data.is_null() { - drop(Box::from_raw(info.wake_sleep_user_data as *mut OWS)); + if info.wake_sleep_callback.is_some() { + info.wake_sleep_user_data.heap_drop_and_dealloc::(); }; - if !info.advance_user_data.is_null() { - drop(Box::from_raw(info.advance_user_data as *mut OA)); + if info.advance_callback.is_some() { + info.advance_user_data.heap_drop_and_dealloc::(); }; } destroy_simulation_event_callbacks(self.as_mut_ptr()); @@ -172,25 +174,22 @@ impl CollisionCallbackRaw for T where T: CollisionCallback {} trait CollisionCallbackRaw: CollisionCallback { unsafe extern "C" fn callback( - user_data: *mut c_void, + mut user_data: UserData, header: *const physx_sys::PxContactPairHeader, pairs: *const physx_sys::PxContactPair, nb_pairs: u32, ) { unsafe { Self::on_collision( - &mut *(user_data as *mut Self), + user_data.heap_data_mut::(), &*header, slice::from_raw_parts(pairs, nb_pairs as usize), ) } } - fn into_cb_user_data(self) -> (Option, *mut c_void) { - ( - Some(Self::callback), - Box::into_raw(Box::new(self)) as *mut c_void, - ) + fn into_cb_user_data(self) -> (Option, UserData) { + (Some(Self::callback), UserData::new_on_heap(self)) } } @@ -203,23 +202,20 @@ impl TriggerCallbackRaw for T where T: TriggerCallback {} trait TriggerCallbackRaw: TriggerCallback { unsafe extern "C" fn callback( - user_data: *mut c_void, + mut user_data: UserData, pairs: *const physx_sys::PxTriggerPair, nb_pairs: u32, ) { unsafe { Self::on_trigger( - &mut *(user_data as *mut Self), + user_data.heap_data_mut::(), slice::from_raw_parts(pairs, nb_pairs as usize), ) } } - fn into_cb_user_data(self) -> (Option, *mut c_void) { - ( - Some(Self::callback), - Box::into_raw(Box::new(self)) as *mut c_void, - ) + fn into_cb_user_data(self) -> (Option, UserData) { + (Some(Self::callback), UserData::new_on_heap(self)) } } @@ -232,23 +228,20 @@ impl ConstraintBreakCallbackRaw for T where T: ConstraintBreakCallback {} trait ConstraintBreakCallbackRaw: ConstraintBreakCallback { unsafe extern "C" fn callback( - this: *mut c_void, + mut user_data: UserData, constraints: *const physx_sys::PxConstraintInfo, nb_constraints: u32, ) { unsafe { Self::on_constraint_break( - &mut *(this as *mut Self), + user_data.heap_data_mut::(), slice::from_raw_parts(constraints, nb_constraints as usize), ) } } - fn into_cb_user_data(self) -> (Option, *mut c_void) { - ( - Some(Self::callback), - Box::into_raw(Box::new(self)) as *mut c_void, - ) + fn into_cb_user_data(self) -> (Option, UserData) { + (Some(Self::callback), UserData::new_on_heap(self)) } } @@ -274,25 +267,22 @@ where D: RigidDynamic, { unsafe extern "C" fn callback( - this: *mut c_void, + mut user_data: UserData, actors: *const *const physx_sys::PxActor, nb_actors: u32, is_waking: bool, ) { unsafe { Self::on_wake_sleep( - &mut *(this as *mut Self), + user_data.heap_data_mut::(), slice::from_raw_parts(actors as *const &ActorMap, nb_actors as usize), is_waking, ); } } - fn into_cb_user_data(self) -> (Option, *mut c_void) { - ( - Some(Self::callback), - Box::into_raw(Box::new(self)) as *mut c_void, - ) + fn into_cb_user_data(self) -> (Option, UserData) { + (Some(Self::callback), UserData::new_on_heap(self)) } } @@ -319,24 +309,21 @@ where D: RigidDynamic, { unsafe extern "C" fn callback( - this: *mut c_void, + user_data: UserData, bodies: *const *const physx_sys::PxRigidBody, transforms: *const physx_sys::PxTransform, nb_actors: u32, ) { unsafe { Self::on_advance( - &*(this as *const _ as *const Self), + user_data.heap_data_ref::(), slice::from_raw_parts(bodies as *const &RigidBodyMap, nb_actors as usize), slice::from_raw_parts(transforms as *const PxTransform, nb_actors as usize), ) } } - fn into_cb_user_data(self) -> (Option, *mut c_void) { - ( - Some(Self::callback), - Box::into_raw(Box::new(self)) as *mut c_void, - ) + fn into_cb_user_data(self) -> (Option, UserData) { + (Some(Self::callback), UserData::new_on_heap(self)) } } diff --git a/physx/src/traits.rs b/physx/src/traits.rs index 0e69715a..1991731f 100644 --- a/physx/src/traits.rs +++ b/physx/src/traits.rs @@ -7,7 +7,7 @@ pub use class::Class; pub(crate) use class::DeriveClassForNewType; mod user_data; -pub(crate) use user_data::UserData; +pub(crate) use user_data::HasUserData; pub mod descriptor; pub(crate) use descriptor::*; diff --git a/physx/src/traits/descriptor.rs b/physx/src/traits/descriptor.rs index 4a7cf6f7..86d5cf15 100644 --- a/physx/src/traits/descriptor.rs +++ b/physx/src/traits/descriptor.rs @@ -19,11 +19,11 @@ use crate::{ AdvanceCallback, CollisionCallback, ConstraintBreakCallback, PxSimulationEventCallback, TriggerCallback, WakeSleepCallback, }, - traits::UserData, + traits::HasUserData, }; pub use physx_sys::PxSceneFlags as SceneFlags; -use physx_sys::UserDataField; +use physx_sys::UserData; use std::{marker::PhantomData, ptr::null_mut}; @@ -183,7 +183,7 @@ impl< frictionOffsetThreshold: self.friction_offset_threshold, ccdMaxSeparation: self.ccd_max_separation, flags: self.flags, - userData: UserDataField::new_with_data(self.user_data), + userData: UserData::new_maybe_packed(self.user_data), solverBatchSize: self.solver_batch_size, solverArticulationBatchSize: self.solver_articulation_batch_size, maxBiasCoefficient: self.max_bias_coefficient, @@ -278,7 +278,7 @@ pub struct MaterialDescriptor { } impl Descriptor

- for MaterialDescriptor<<<

::Shape as Shape>::Material as UserData>::UserData> + for MaterialDescriptor<<<

::Shape as Shape>::Material as HasUserData>::UserData> { type Target = Option::Shape as Shape>::Material>>; fn create(self, physics: &mut P) -> Self::Target { @@ -300,7 +300,7 @@ pub struct ShapeDescriptor<'a, U, G: Geometry, M: Material> { } impl Descriptor

- for ShapeDescriptor<'_, ::UserData, G, ::Material> + for ShapeDescriptor<'_, ::UserData, G, ::Material> { type Target = Option>; diff --git a/physx/src/traits/user_data.rs b/physx/src/traits/user_data.rs index 83964d89..306ce3d6 100644 --- a/physx/src/traits/user_data.rs +++ b/physx/src/traits/user_data.rs @@ -1,53 +1,77 @@ -use physx_sys::UserDataField; +use physx_sys::UserData; -/// UserData allows easy access and initialization of userData *mut c_void fields on Px objects. -/// Not all Px objects with user data expose them as a field, so not all objects with user data can use this. +/// `HasUserData` allows easy access and initialization of `void* userData` (in Rust, `UserData`) +/// fields on Px objects. /// -/// # Safety +/// Not all Px objects with user data expose them as a field, so not all +/// objects with user data can use this. Objects which only allow getting the user data through +/// an accessor function cannot use this trait because returning a (mutable) reference to the +/// user data field itself isn't possible. /// -/// all constructors of implementing types must call `init_user_data` during construction. -/// If this does not happen, calling get_user_data or get_user_data_mut may return garbage data, or -/// dereference an invalid pointer. If UserData is larger than a *mut ptr it will be stored on the heap, -/// and it may need to be explicitly dropped by turning the field back into a Box and dropping it. -/// If UserData implements Drop, this may be as simple as calling `get_user_data_mut` and then calling drop(), -/// but implementation is left to the concrete type's Drop impl. -pub unsafe trait UserData: Sized { +/// The default implementations try to exploit packing `UserData` into the space of the pointer +/// field itself. If `UserData` has larger size or alignment than a pointer, it will be stored +/// on the heap. Other implementations may modify this behavior to, for example, always store the +/// data on the heap, if it suits them. An example of this are the `Px__ControllerDesc` objects, +/// which will be used to create `Px__Controller`s that implement the `Controller` trait. That +/// `Controller` trait expects the user data to always be on the heap because it is one of the +/// objects for which user data is only accessible through an acessor method. As such, the +/// `Desc` objects must follow suit and always place the data on the heap. +pub trait HasUserData: Sized { type UserData; /// Returns a reference to the userData field - fn user_data_ptr(&self) -> &UserDataField; + fn user_data_ptr(&self) -> &UserData; /// Returns a mutable reference to the userData field. - fn user_data_ptr_mut(&mut self) -> &mut UserDataField; + fn user_data_ptr_mut(&mut self) -> &mut UserData; + /// Initialize the user data #[inline(always)] fn init_user_data(&mut self, user_data: Self::UserData) -> &mut Self { - self.user_data_ptr_mut().initialize_with_data::(user_data); + self.user_data_ptr_mut() + .initialize_maybe_packed::(user_data); self } + /// Drop and dealloc the user data + /// /// # Safety /// /// The user data field must have previously been initialized via `init_user_data` #[inline(always)] unsafe fn drop_and_dealloc_user_data(&mut self) { // SAFETY: same as function-level safety - unsafe { self.user_data_ptr_mut().drop_and_dealloc::() } + unsafe { + self.user_data_ptr_mut() + .maybe_packed_drop_and_dealloc::() + } } + /// Get a shared ref to the user data, whether packed in the pointer or on the heap. + /// /// # Safety /// /// The user data field must have previously been initialized via `init_user_data`. #[inline(always)] unsafe fn get_user_data(&self) -> &Self::UserData { - unsafe { self.user_data_ptr().data_ref::() } + // SAFETY: same as function-level safety + unsafe { + self.user_data_ptr() + .maybe_packed_data_ref::() + } } + /// Get a mutable ref to the user data, whether packed in the pointer or on the heap. + /// /// # Safety /// /// The user data field must have previously been initialized via `init_user_data`. #[inline(always)] unsafe fn get_user_data_mut(&mut self) -> &mut Self::UserData { - unsafe { self.user_data_ptr_mut().data_ref_mut::() } + // SAFETY: same as function-level safety + unsafe { + self.user_data_ptr_mut() + .maybe_packed_data_mut::() + } } } @@ -55,12 +79,12 @@ pub unsafe trait UserData: Sized { mod tests { use std::{fmt::Debug, marker::PhantomData}; - use physx_sys::UserDataField; + use physx_sys::UserData; - use super::UserData; + use super::HasUserData; struct TestUserData { - user_data: UserDataField, + user_data: UserData, phantom: PhantomData, } @@ -73,14 +97,14 @@ mod tests { } } - unsafe impl UserData for TestUserData { + impl HasUserData for TestUserData { type UserData = U; - fn user_data_ptr(&self) -> &UserDataField { + fn user_data_ptr(&self) -> &UserData { &self.user_data } - fn user_data_ptr_mut(&mut self) -> &mut UserDataField { + fn user_data_ptr_mut(&mut self) -> &mut UserData { &mut self.user_data } } @@ -90,8 +114,8 @@ mod tests { let mut object: TestUserData = TestUserData::default(); object.init_user_data(user_data.clone()); - assert_eq!(UserData::get_user_data(&object), &user_data); - assert_eq!(UserData::get_user_data_mut(&mut object), &user_data); + assert_eq!(HasUserData::get_user_data(&object), &user_data); + assert_eq!(HasUserData::get_user_data_mut(&mut object), &user_data); object.drop_and_dealloc_user_data(); }