Commit a0e7f494 authored by Luke Jones's avatar Luke Jones

Use ptr::NonNull for some pointer safety guarantees.

Signed-off-by: default avatarLuke Jones <jones_ld@protonmail.com>
parent e58e67eb
Pipeline #65449712 passed with stage
in 1 minute and 52 seconds
......@@ -5,8 +5,8 @@ use std::ptr;
#[derive(Copy, Clone)]
pub struct Contact {
pub first: *mut Particle,
pub second: Option<*mut Particle>,
pub first: ptr::NonNull<Particle>,
pub second: Option<ptr::NonNull<Particle>>,
pub first_move: Vec2d<FP>,
pub second_move: Vec2d<FP>,
pub restitution: FP,
......@@ -17,7 +17,7 @@ pub struct Contact {
impl Default for Contact {
fn default() -> Contact {
Contact {
first: ptr::null_mut(),
first: ptr::NonNull::dangling(),
second: None,
first_move: Vec2d::default(),
second_move: Vec2d::default(),
......@@ -65,7 +65,7 @@ impl ContactGenerator for GroundContact {
let y = particle.position().y();
if y < 0.0 {
contacts[index].contact_normal = Vec2d::new(0.0, 1.0);
contacts[index].first = particle.as_mut_ptr();
contacts[index].first = particle.as_non_null_ptr();
contacts[index].second = None;
contacts[index].penetration = -y;
contacts[index].restitution = 0.3;
......@@ -136,7 +136,7 @@ impl ContactGenerator for AreaContact {
}
if contact_made {
contacts[index].first = particle.as_mut_ptr();
contacts[index].first = particle.as_non_null_ptr();
contacts[index].second = None;
contacts[index].restitution = 0.3;
count += 1;
......@@ -158,15 +158,15 @@ impl ContactGenerator for AreaContact {
/// Simulates a cable which is slack until it reaches its maximum length.
/// The cable joins two particles together.
pub struct Cable {
particles: [*mut Particle; 2],
particles: [ptr::NonNull<Particle>; 2],
max_length: FP,
restitution: FP,
}
impl Cable {
pub fn new(
p1: *mut Particle,
p2: *mut Particle,
p1: ptr::NonNull<Particle>,
p2: ptr::NonNull<Particle>,
len: FP,
restitution: FP,
) -> Cable {
......@@ -178,8 +178,8 @@ impl Cable {
}
fn get_current_len(&self) -> FP {
let p0 = unsafe { &*self.particles[0] };
let p1 = unsafe { &*self.particles[1] };
let p0 = unsafe { self.particles[0].as_ref() };
let p1 = unsafe { self.particles[1].as_ref() };
(p0.position() - p1.position()).magnitude()
}
}
......@@ -198,8 +198,8 @@ impl ContactGenerator for Cable {
let mut contact = &mut contacts[0];
let p0 = unsafe { &*self.particles[0] };
let p1 = unsafe { &*self.particles[1] };
let p0 = unsafe { self.particles[0].as_ref() };
let p1 = unsafe { self.particles[1].as_ref() };
contact.first = self.particles[0];
contact.second = Some(self.particles[1]);
......@@ -211,7 +211,7 @@ impl ContactGenerator for Cable {
}
fn contains_ptr(&self, ptr: usize) -> bool {
for p in self.particles.iter() {
if *p as usize == ptr {
if p.as_ptr() as usize == ptr {
return true;
}
}
......@@ -222,7 +222,7 @@ impl ContactGenerator for Cable {
/// Simulates a cable which is slack until it reaches its maximum length.
/// This version can anchor to any point specified by a `Vec2d`.
pub struct CableConstraint {
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
anchor: Vec2d<FP>,
max_length: FP,
restitution: FP,
......@@ -230,7 +230,7 @@ pub struct CableConstraint {
impl CableConstraint {
pub fn new(
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
anchor: Vec2d<FP>,
len: FP,
restitution: FP,
......@@ -244,7 +244,7 @@ impl CableConstraint {
}
fn get_current_len(&self) -> FP {
let p = unsafe { &*self.particle };
let p = unsafe { self.particle.as_ref() };
(p.position() - self.anchor).magnitude()
}
}
......@@ -263,7 +263,7 @@ impl ContactGenerator for CableConstraint {
let mut contact = &mut contacts[0];
let p = unsafe { &*self.particle };
let p = unsafe { self.particle.as_ref() };
contact.first = self.particle;
contact.second = None;
......@@ -274,22 +274,22 @@ impl ContactGenerator for CableConstraint {
1
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle as usize == ptr
self.particle.as_ptr() as usize == ptr
}
}
/// A rod simulates a hard constraint where the distance of two particles
/// can not be above or below the length specified.
pub struct Rod {
particles: [*mut Particle; 2],
particles: [ptr::NonNull<Particle>; 2],
length: FP,
restitution: FP,
}
impl Rod {
pub fn new(
p1: *mut Particle,
p2: *mut Particle,
p1: ptr::NonNull<Particle>,
p2: ptr::NonNull<Particle>,
length: FP,
restitution: FP,
) -> Rod {
......@@ -301,8 +301,8 @@ impl Rod {
}
fn get_current_len(&self) -> FP {
let p0 = unsafe { &*self.particles[0] };
let p1 = unsafe { &*self.particles[1] };
let p0 = unsafe { self.particles[0].as_ref() };
let p1 = unsafe { self.particles[1].as_ref() };
(p0.position() - p1.position()).magnitude()
}
}
......@@ -324,8 +324,8 @@ impl ContactGenerator for Rod {
contact.second = Some(self.particles[1]);
contact.restitution = self.restitution;
let p0 = unsafe { &*self.particles[0] };
let p1 = unsafe { &*self.particles[1] };
let p0 = unsafe { self.particles[0].as_ref() };
let p1 = unsafe { self.particles[1].as_ref() };
let normal = (p1.position() - p0.position()).normalise();
......@@ -340,7 +340,7 @@ impl ContactGenerator for Rod {
}
fn contains_ptr(&self, ptr: usize) -> bool {
for p in self.particles.iter() {
if *p as usize == ptr {
if p.as_ptr() as usize == ptr {
return true;
}
}
......@@ -352,7 +352,7 @@ impl ContactGenerator for Rod {
/// can not be above or below the length specified. This version may be
/// anchored to any point specified by a `Vec2d`
pub struct RodConstraint {
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
anchor: Vec2d<FP>,
length: FP,
restitution: FP,
......@@ -360,7 +360,7 @@ pub struct RodConstraint {
impl RodConstraint {
pub fn new(
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
anchor: Vec2d<FP>,
length: FP,
restitution: FP,
......@@ -374,7 +374,7 @@ impl RodConstraint {
}
fn get_current_len(&self) -> FP {
let p = unsafe { &*self.particle };
let p = unsafe { self.particle.as_ref() };
(p.position() - self.anchor).magnitude()
}
}
......@@ -396,7 +396,7 @@ impl ContactGenerator for RodConstraint {
contact.second = None;
contact.restitution = self.restitution;
let p = unsafe { &*self.particle };
let p = unsafe { self.particle.as_ref() };
let normal = (self.anchor - p.position()).normalise();
if current_length > self.length {
......@@ -409,6 +409,6 @@ impl ContactGenerator for RodConstraint {
1
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle as usize == ptr
self.particle.as_ptr() as usize == ptr
}
}
......@@ -89,14 +89,14 @@ impl Contact {
#[inline]
fn calc_separating_velocity(&self) -> FP {
let mut relative_velocity = unsafe { (*self.first).velocity() };
let mut relative_velocity = unsafe { self.first.as_ref().velocity() };
if let Some(second) = self.second {
relative_velocity -= unsafe { (*second).velocity() }
relative_velocity -= unsafe { second.as_ref().velocity() }
};
relative_velocity * self.contact_normal
}
fn resolve_velocity(&self, dt: FP) {
fn resolve_velocity(&mut self, dt: FP) {
// Find the velocity in the direction of the contact
let separating_v = self.calc_separating_velocity();
// Check if it needs to be resolved
......@@ -112,9 +112,10 @@ impl Contact {
// Check the velocity build-up due to acceleration only
// This process tries to solve resting contacts with
// micro-collisions
let mut acc_caused_velocity = unsafe { (*self.first).acceleration() };
let mut acc_caused_velocity =
unsafe { self.first.as_mut().acceleration() };
if let Some(second) = self.second {
acc_caused_velocity -= unsafe { (*second).acceleration() };
acc_caused_velocity -= unsafe { second.as_ref().acceleration() };
}
let acc_caused_sep_vel = acc_caused_velocity * self.contact_normal * dt;
......@@ -146,13 +147,13 @@ impl Contact {
// Apply impulses: they are applied in the direction of the contact,
// and are proportional to the inverse mass.
let first = unsafe { &mut *(self.first) };
let first = unsafe { self.first.as_mut() };
first.set_velocity(
first.velocity() + impulse_per_imass * first.inverse_mass(),
);
if let Some(second) = self.second {
let second = unsafe { &mut *(second) };
if let Some(second) = self.second.as_mut() {
let second = unsafe { second.as_mut() };
second.set_velocity(
second.velocity() + impulse_per_imass * -second.inverse_mass(),
);
......@@ -160,10 +161,10 @@ impl Contact {
}
#[inline]
fn get_total_inverse_mass(&self) -> FP {
let mut total = unsafe { (*self.first).inverse_mass() };
fn get_total_inverse_mass(&mut self) -> FP {
let mut total = unsafe { self.first.as_mut().inverse_mass() };
if let Some(second) = self.second {
total += unsafe { (*second).inverse_mass() };
total += unsafe { second.as_ref().inverse_mass() };
}
total
}
......@@ -188,19 +189,19 @@ impl Contact {
// Calculate the the movement amounts
self.first_move =
move_per_imass * unsafe { (*self.first).inverse_mass() };
move_per_imass * unsafe { self.first.as_ref().inverse_mass() };
if let Some(second) = self.second {
self.second_move =
move_per_imass * unsafe { -(*second).inverse_mass() };
move_per_imass * unsafe { -second.as_ref().inverse_mass() };
} else {
self.second_move.clear();
}
// Apply penetration resolution to positions
let first = unsafe { &mut *self.first };
let first = unsafe { self.first.as_mut() };
first.set_position(first.position() + self.first_move);
if let Some(second) = self.second {
let second = unsafe { &mut *(second) };
if let Some(second) = self.second.as_mut() {
let second = unsafe { second.as_mut() };
second.set_position(second.position() + self.second_move);
};
}
......
use crate::particle::Particle;
use crate::vec2d::Vec2d;
use crate::FP;
use std::ptr;
pub trait ForceGenerator {
fn update_force(&self);
fn update_force(&mut self);
fn contains_ptr(&self, ptr: usize) -> bool;
}
/////////////////////////////////////////////////////////////////////////////////
pub struct Gravity {
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
gravity: FP,
}
impl Gravity {
pub fn new(particle: *mut Particle, gravity: FP) -> Gravity {
pub fn new(particle: ptr::NonNull<Particle>, gravity: FP) -> Gravity {
Gravity { particle, gravity }
}
}
impl ForceGenerator for Gravity {
fn update_force(&self) {
let particle = unsafe { &mut *self.particle };
fn update_force(&mut self) {
let particle = unsafe { self.particle.as_mut() };
let force = Vec2d::new(0.0, self.gravity * particle.mass());
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle as usize == ptr
self.particle.as_ptr() as usize == ptr
}
}
/////////////////////////////////////////////////////////////////////////////////
pub struct Drag {
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
k1: FP,
k2: FP,
}
impl Drag {
pub fn new(particle: *mut Particle, k1: FP, k2: FP) -> Drag {
pub fn new(particle: ptr::NonNull<Particle>, k1: FP, k2: FP) -> Drag {
Drag { particle, k1, k2 }
}
}
impl ForceGenerator for Drag {
fn update_force(&self) {
let particle = unsafe { &mut *self.particle };
fn update_force(&mut self) {
let particle = unsafe { self.particle.as_mut() };
let mut force = particle.velocity();
let mut drag_coeff = force.magnitude();
drag_coeff = self.k1 * drag_coeff + self.k2 * drag_coeff * drag_coeff;
......@@ -50,20 +51,20 @@ impl ForceGenerator for Drag {
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle as usize == ptr
self.particle.as_ptr() as usize == ptr
}
}
/////////////////////////////////////////////////////////////////////////////////
pub struct AnchoredSpring {
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
anchor: Vec2d<FP>,
spring_const: FP,
rest_len: FP,
}
impl AnchoredSpring {
pub fn new(
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
anchor: Vec2d<FP>,
spring_const: FP,
rest_len: FP,
......@@ -77,8 +78,8 @@ impl AnchoredSpring {
}
}
impl ForceGenerator for AnchoredSpring {
fn update_force(&self) {
let particle = unsafe { &mut *self.particle };
fn update_force(&mut self) {
let particle = unsafe { self.particle.as_mut() };
// Calculate the vector of the spring
let mut force = particle.position();
force -= self.anchor;
......@@ -91,21 +92,21 @@ impl ForceGenerator for AnchoredSpring {
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle as usize == ptr
self.particle.as_ptr() as usize == ptr
}
}
/////////////////////////////////////////////////////////////////////////////////
pub struct AnchoredBungee {
particle: *mut Particle,
anchor: *mut Particle,
particle: ptr::NonNull<Particle>,
anchor: ptr::NonNull<Particle>,
spring_const: FP,
rest_len: FP,
}
impl AnchoredBungee {
pub fn new(
particle: *mut Particle,
anchor: *mut Particle,
particle: ptr::NonNull<Particle>,
anchor: ptr::NonNull<Particle>,
spring_const: FP,
rest_len: FP,
) -> AnchoredBungee {
......@@ -118,9 +119,9 @@ impl AnchoredBungee {
}
}
impl ForceGenerator for AnchoredBungee {
fn update_force(&self) {
let pos = unsafe { (*self.anchor).position() };
let particle = unsafe { &mut *self.particle };
fn update_force(&mut self) {
let pos = unsafe { self.anchor.as_ref().position() };
let particle = unsafe { self.particle.as_mut() };
// Calculate the vector of the spring
let mut force = particle.position();
force -= pos;
......@@ -139,13 +140,14 @@ impl ForceGenerator for AnchoredBungee {
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle as usize == ptr || self.anchor as usize == ptr
self.particle.as_ptr() as usize == ptr
|| self.anchor.as_ptr() as usize == ptr
}
}
/////////////////////////////////////////////////////////////////////////////////
pub struct Buoyancy {
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
max_depth: FP,
volume: FP,
water_height: FP,
......@@ -153,7 +155,7 @@ pub struct Buoyancy {
}
impl Buoyancy {
pub fn new(
particle: *mut Particle,
particle: ptr::NonNull<Particle>,
max_depth: FP,
volume: FP,
water_height: FP,
......@@ -169,8 +171,8 @@ impl Buoyancy {
}
}
impl ForceGenerator for Buoyancy {
fn update_force(&self) {
let particle = unsafe { &mut *self.particle };
fn update_force(&mut self) {
let particle = unsafe { self.particle.as_mut() };
let depth = particle.position().y();
// check if out of water
......@@ -197,6 +199,6 @@ impl ForceGenerator for Buoyancy {
particle.add_force(force);
}
fn contains_ptr(&self, ptr: usize) -> bool {
self.particle as usize == ptr
self.particle.as_ptr() as usize == ptr
}
}
......@@ -43,7 +43,7 @@ impl ForceRegistry {
/// Calls the `update_force()` method on all forces in the registry
pub fn update_forces(&mut self) {
for fg in &self.registrations {
for fg in &mut self.registrations {
fg.update_force();
}
}
......
use crate::vec2d::Vec2d;
use crate::FP;
use std::ptr;
#[derive(Debug)]
pub struct Particle {
......@@ -102,15 +103,9 @@ impl Particle {
}
#[inline]
pub fn as_ptr(&self) -> *const Particle {
let x: *const Particle = self;
x
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut Particle {
pub fn as_non_null_ptr(&mut self) -> ptr::NonNull<Particle> {
let x: *mut Particle = self;
x
unsafe { ptr::NonNull::new_unchecked(x) }
}
}
......
......@@ -6,6 +6,7 @@ use crate::{
particle::Particle,
FP,
};
use std::ptr;
use vec2d::Vec2d;
/// The `World` contains the many parts of a physics engine, such
......@@ -81,8 +82,7 @@ impl World {
Some(slot)
}
/// Get a reference to `Particle` located at index number (`id`). This
/// method is intended
/// Get a reference to `Particle` located at index number (`id`).
#[inline]
pub fn get_particle_position(&self, id: usize) -> Option<Vec2d<FP>> {
if let Some(p) = self.particle_array.get(id) {
......@@ -94,11 +94,33 @@ impl World {
}
#[inline]
pub fn get_particle_ptr(&mut self, ptr: usize) -> Option<*mut Particle> {
if let Some(p) = self.particle_array.get_mut(ptr) {
pub fn get_particle(&self, id: usize) -> Option<&Particle> {
if let Some(p) = self.particle_array.get(id) {
if p.is_some() {
return p.as_ref();
}
}
None
}
#[inline]
pub fn get_particle_mut(&mut self, id: usize) -> Option<&mut Particle> {
if let Some(p) = self.particle_array.get_mut(id) {
if p.is_some() {
return p.as_mut();
}
}
None
}
#[inline]
pub fn get_particle_ptr(
&mut self,
id: usize,
) -> Option<ptr::NonNull<Particle>> {
if let Some(p) = self.particle_array.get_mut(id) {
if let Some(p) = p.as_mut() {
let ptr: *mut Particle = p;
return Some(ptr);
return Some(p.as_non_null_ptr());
}
}
None
......@@ -108,10 +130,11 @@ impl World {
pub fn rm_particle(&mut self, id: usize) {
// TODO: get pointer from id, check generators for use
if id < self.particle_array.len() - 1 {
if let Some(slot) = self.particle_array.get(id) {
if let Some(slot) = self.particle_array.get_mut(id) {
if let Some(particle) = slot {
// make the pointer a usize for comparisons
let ptr_uzise = particle.as_ptr() as usize;
let ptr_uzise =
particle.as_non_null_ptr().as_ptr() as usize;
// do registry first
self.registry.remove_if_contains(ptr_uzise);
// need to loop, remove, reset since the array changes
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment