boxdd 0.6.0

Safe, ergonomic Rust bindings for Box2D v3
Documentation
use crate::error::{Error, Result};
use crate::types::BodyId;
use crate::world::BodyProof;
use boxdd_sys::ffi;

use super::scoped::Body;

mod attachments;
mod dynamics;
mod mass;
mod metadata;
mod relations;
mod state;
mod transform;
mod user_data;

pub(crate) use transform::body_position_impl;

#[inline]
pub(crate) fn raw_body_id(id: BodyId) -> ffi::b2BodyId {
    id.into_raw()
}

#[inline]
pub(crate) fn check_native_body_finite(
    operation: &'static str,
    output: &'static str,
    value: f32,
) -> Result<f32> {
    if value.is_finite() {
        Ok(value)
    } else {
        Err(Error::InvalidNativeOutput {
            operation,
            output,
            constraint: "a finite value",
        })
    }
}

#[inline]
pub(crate) fn check_native_body_non_negative(
    operation: &'static str,
    output: &'static str,
    value: f32,
) -> Result<f32> {
    if value.is_finite() && value >= 0.0 {
        Ok(value)
    } else {
        Err(Error::InvalidNativeOutput {
            operation,
            output,
            constraint: "a finite non-negative value",
        })
    }
}

#[inline]
pub(crate) fn check_native_body_count(
    operation: &'static str,
    output: &'static str,
    value: i32,
) -> Result<i32> {
    if value >= 0 {
        Ok(value)
    } else {
        Err(Error::InvalidNativeOutput {
            operation,
            output,
            constraint: "a non-negative native int",
        })
    }
}

impl Body<'_> {
    #[inline]
    fn body_id(&self) -> BodyId {
        self.proof.id()
    }

    #[inline]
    fn body_access(&self) -> &BodyProof<'_> {
        &self.proof
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn native_body_scalar_and_count_checks_fail_closed() {
        assert_eq!(
            check_native_body_finite("Body::angular_velocity", "angular_velocity", f32::NAN),
            Err(Error::InvalidNativeOutput {
                operation: "Body::angular_velocity",
                output: "angular_velocity",
                constraint: "a finite value",
            })
        );
        assert_eq!(
            check_native_body_non_negative("Body::mass", "mass", -1.0),
            Err(Error::InvalidNativeOutput {
                operation: "Body::mass",
                output: "mass",
                constraint: "a finite non-negative value",
            })
        );
        assert_eq!(
            check_native_body_count("Body::shape_count", "shape_count", -1),
            Err(Error::InvalidNativeOutput {
                operation: "Body::shape_count",
                output: "shape_count",
                constraint: "a non-negative native int",
            })
        );

        assert_eq!(
            check_native_body_finite("Body::gravity_scale", "gravity_scale", -2.0),
            Ok(-2.0)
        );
        assert_eq!(
            check_native_body_non_negative("Body::mass", "mass", f32::INFINITY),
            Err(Error::InvalidNativeOutput {
                operation: "Body::mass",
                output: "mass",
                constraint: "a finite non-negative value",
            })
        );
    }
}