use crate::body::Body;
pub(crate) const STATIC_PARTNER: u32 = u32::MAX;
#[derive(Clone, Copy, Debug)]
pub(crate) struct Slot {
pub(crate) generation: u32,
pub(crate) body: Option<Body>,
}
impl Slot {
pub(crate) fn get(&self) -> Option<&Body> {
self.body.as_ref()
}
pub(crate) fn get_mut(&mut self) -> Option<&mut Body> {
self.body.as_mut()
}
}
pub(crate) fn constraint_bodies(
slots: &mut [Slot],
first: usize,
second: usize,
) -> Option<(&mut Body, Option<&mut Body>)> {
if second == STATIC_PARTNER as usize {
let body = slots.get_mut(first)?.get_mut()?;
return Some((body, None));
}
if first == second {
return None;
}
let (low, high) = if first < second {
(first, second)
} else {
(second, first)
};
if high >= slots.len() {
return None;
}
let (left, right) = slots.split_at_mut(high);
let high_body = right.first_mut()?.get_mut()?;
let low_body = left.get_mut(low)?.get_mut()?;
if first < second {
Some((low_body, Some(high_body)))
} else {
Some((high_body, Some(low_body)))
}
}
pub(crate) fn constraint_bodies_ref(
slots: &[Slot],
first: usize,
second: usize,
) -> Option<(&Body, Option<&Body>)> {
let first_body = slots.get(first)?.get()?;
if second == STATIC_PARTNER as usize {
return Some((first_body, None));
}
let second_body = slots.get(second)?.get()?;
Some((first_body, Some(second_body)))
}
#[cfg(test)]
mod tests {
use super::{STATIC_PARTNER, Slot, constraint_bodies};
use crate::body::BodyDesc;
use crate::shape::Shape;
fn slots(count: usize) -> alloc::vec::Vec<Slot> {
(0..count)
.map(|_| Slot {
generation: 0,
body: Some(crate::body::Body::from_desc(&BodyDesc::dynamic(
Shape::sphere(0.5),
1.0,
))),
})
.collect()
}
#[test]
fn constraint_bodies_returns_them_in_the_requested_order() {
let mut storage = slots(3);
let (first, second) = constraint_bodies(&mut storage, 0, 2).expect("both exist");
first.linear_velocity.x = 1.0;
second.expect("second exists").linear_velocity.x = 2.0;
let (reversed_first, _) = constraint_bodies(&mut storage, 2, 0).expect("both exist");
assert!((reversed_first.linear_velocity.x - 2.0).abs() < 1e-6);
}
#[test]
fn a_static_partner_yields_a_single_body() {
let mut storage = slots(1);
let (first, second) =
constraint_bodies(&mut storage, 0, STATIC_PARTNER as usize).expect("the body exists");
assert!(second.is_none(), "immovable geometry has no Body");
first.linear_velocity.x = 3.0;
assert!((storage[0].get().expect("body").linear_velocity.x - 3.0).abs() < 1e-6);
}
#[test]
fn constraint_bodies_rejects_self_and_missing_slots() {
let mut storage = slots(2);
assert!(constraint_bodies(&mut storage, 1, 1).is_none());
assert!(constraint_bodies(&mut storage, 0, 9).is_none());
storage[1].body = None;
assert!(constraint_bodies(&mut storage, 0, 1).is_none());
}
}