use crate::core::{box3d_lock, callback_state, debug_checks, validation};
use crate::error::{Error, Result};
use crate::joints::lock_joint_checked;
use crate::types::{BodyId, ContactId, JointId, ShapeId};
use crate::world::World;
use boxddd_sys::ffi;
use std::ffi::c_void;
use std::fmt;
pub struct WorldRawGuard<'a> {
world: &'a mut World,
_lock: std::sync::MutexGuard<'static, ()>,
}
impl fmt::Debug for WorldRawGuard<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("WorldRawGuard")
.finish_non_exhaustive()
}
}
impl WorldRawGuard<'_> {
pub fn world_id(&self) -> ffi::b3WorldId {
self.world.raw()
}
pub fn body_id(&self, id: BodyId) -> Result<ffi::b3BodyId> {
self.world.state.ledger.authorize_body(id)
}
pub fn shape_id(&self, id: ShapeId) -> Result<ffi::b3ShapeId> {
self.world.state.ledger.authorize_shape(id)
}
pub fn joint_id(&self, id: JointId) -> Result<ffi::b3JointId> {
self.world.state.ledger.authorize_joint(id)
}
pub fn contact_id(&self, id: ContactId) -> Result<ffi::b3ContactId> {
let raw = self.world.state.ledger.authorize_contact(id)?;
debug_checks::check_contact_valid_raw(raw)?;
Ok(raw)
}
}
#[must_use = "dropping raw world parts destroys the native world and all retained sidecars"]
#[derive(Debug)]
pub struct WorldRawParts {
world: Option<World>,
}
impl WorldRawParts {
pub unsafe fn world_guard(&mut self) -> Result<WorldRawGuard<'_>> {
let world = self.world.as_mut().ok_or(Error::NativeFailure)?;
unsafe { world_raw_guard(world) }
}
pub unsafe fn into_world(mut self) -> Result<World> {
callback_state::check_not_in_callback()?;
{
let world = self.world.as_ref().ok_or(Error::NativeFailure)?;
let _guard = box3d_lock::lock();
world.check_world_valid_locked()?;
}
Ok(self.world.take().expect("raw parts still own their world"))
}
pub unsafe fn destroy(self) {
drop(self);
}
}
impl World {
pub fn into_raw_parts(self) -> Result<WorldRawParts> {
callback_state::check_not_in_callback()?;
{
let _guard = box3d_lock::lock();
self.check_world_valid_locked()?;
}
Ok(WorldRawParts { world: Some(self) })
}
}
pub unsafe fn world_raw_guard(world: &mut World) -> Result<WorldRawGuard<'_>> {
callback_state::check_not_in_callback()?;
let lock = box3d_lock::lock();
world.check_world_valid_locked()?;
Ok(WorldRawGuard { world, _lock: lock })
}
pub unsafe fn set_world_raw_user_data(world: &mut World, user_data: *mut c_void) -> Result<()> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
world.check_world_valid_locked()?;
unsafe { ffi::b3World_SetUserData(world.raw(), user_data) };
Ok(())
}
pub unsafe fn world_raw_user_data(world: &World) -> Result<*mut c_void> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
world.check_world_valid_locked()?;
Ok(unsafe { ffi::b3World_GetUserData(world.raw()) })
}
pub unsafe fn set_body_raw_user_data(
world: &mut World,
body_id: BodyId,
user_data: *mut c_void,
) -> Result<()> {
let _guard = world.lock_body_checked(body_id)?;
unsafe { ffi::b3Body_SetUserData(body_id.into_raw(), user_data) };
Ok(())
}
pub unsafe fn body_raw_user_data(world: &World, body_id: BodyId) -> Result<*mut c_void> {
let _guard = world.lock_body_checked(body_id)?;
Ok(unsafe { ffi::b3Body_GetUserData(body_id.into_raw()) })
}
pub unsafe fn set_shape_raw_user_data(
world: &mut World,
shape_id: ShapeId,
user_data: *mut c_void,
) -> Result<()> {
let _guard = world.lock_shape_checked(shape_id)?;
unsafe { ffi::b3Shape_SetUserData(shape_id.into_raw(), user_data) };
Ok(())
}
pub unsafe fn shape_raw_user_data(world: &World, shape_id: ShapeId) -> Result<*mut c_void> {
let _guard = world.lock_shape_checked(shape_id)?;
Ok(unsafe { ffi::b3Shape_GetUserData(shape_id.into_raw()) })
}
pub unsafe fn set_joint_raw_user_data(
world: &mut World,
joint_id: JointId,
user_data: *mut c_void,
) -> Result<()> {
let _guard = lock_joint_checked(world, joint_id)?;
unsafe { ffi::b3Joint_SetUserData(joint_id.into_raw(), user_data) };
Ok(())
}
pub unsafe fn joint_raw_user_data(world: &World, joint_id: JointId) -> Result<*mut c_void> {
let _guard = lock_joint_checked(world, joint_id)?;
Ok(unsafe { ffi::b3Joint_GetUserData(joint_id.into_raw()) })
}
pub fn length_units_per_meter() -> Result<f32> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
let value = unsafe { ffi::b3GetLengthUnitsPerMeter() };
if value.is_finite() && value > 0.0 {
Ok(value)
} else {
Err(Error::NativeFailure)
}
}
pub fn set_length_units_per_meter(length_units: f32) -> Result<()> {
validation::positive("raw.length_units_per_meter", length_units)?;
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
unsafe { ffi::b3SetLengthUnitsPerMeter(length_units) };
Ok(())
}
pub fn stall_threshold() -> Result<f32> {
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
let value = unsafe { ffi::b3GetStallThreshold() };
if value.is_finite() && value >= 0.0 {
Ok(value)
} else {
Err(Error::NativeFailure)
}
}
pub fn set_stall_threshold(seconds: f32) -> Result<()> {
validation::nonnegative("raw.stall_threshold", seconds)?;
callback_state::check_not_in_callback()?;
let _guard = box3d_lock::lock();
unsafe { ffi::b3SetStallThreshold(seconds) };
Ok(())
}