boxdd 0.6.0

Safe, ergonomic Rust bindings for Box2D v3
Documentation
use super::*;

unsafe fn try_read_sensor_output(
    resolver: &crate::core::identity_registry::OutputIdentityResolver<'_>,
    requested: i32,
    fill: impl FnOnce(*mut ffi::b2ShapeId, i32) -> i32,
) -> Result<Vec<ShapeId>> {
    unsafe {
        crate::core::ffi_vec::try_read_mapped_from_ffi(requested, fill, |raw| resolver.shape(raw))
    }
}

pub(crate) fn shape_sensor_overlaps_in_impl(
    shape: crate::world::ShapeCall<'_>,
) -> Result<Vec<ShapeId>> {
    let id = raw_shape_id(shape.id());
    let cap = shape_sensor_capacity_impl("Shape::sensor_overlaps", shape.id())?;
    shape.with_output_identity_resolver(|resolver| unsafe {
        try_read_sensor_output(resolver, cap, |ptr, cap| {
            ffi::b2Shape_GetSensorData(id, ptr, cap)
        })
    })
}

#[inline]
pub(crate) fn shape_sensor_capacity_impl(operation: &'static str, id: ShapeId) -> Result<i32> {
    check_native_shape_sensor_capacity(
        operation,
        unsafe { ffi::b2Shape_GetSensorCapacity(raw_shape_id(id)) },
        shape_is_sensor_impl(id),
    )
}

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

    fn test_registry() -> (
        crate::id::IdBrand,
        std::sync::Arc<crate::core::identity_registry::ActiveIdentityRegistry>,
    ) {
        let brand = crate::id::IdBrand::new(
            ffi::b2WorldId {
                index1: 4,
                generation: 7,
            },
            crate::id::WorldToken::allocate().unwrap(),
        )
        .unwrap();
        let registry = crate::core::identity_registry::ActiveIdentityRegistry::new(brand);
        let body = registry
            .register_body(ffi::b2BodyId {
                index1: 1,
                world0: brand.world0(),
                generation: 1,
            })
            .unwrap();
        for index1 in [2, 9] {
            registry
                .register_shape(raw_shape(index1, brand.world0()), body)
                .unwrap();
        }
        (brand, registry)
    }

    fn raw_shape(index1: i32, world0: u16) -> ffi::b2ShapeId {
        ffi::b2ShapeId {
            index1,
            world0,
            generation: 1,
        }
    }

    #[test]
    fn sensor_output_rejects_invalid_ids() {
        let (brand, registry) = test_registry();
        let error = registry
            .with_output_resolver(|resolver| unsafe {
                try_read_sensor_output(resolver, 1, |ptr, _capacity| {
                    ptr.write(raw_shape(1, brand.world0().wrapping_add(1)));
                    1
                })
            })
            .unwrap_err();
        assert_eq!(error, Error::WrongWorld);

        let error = registry
            .with_output_resolver(|resolver| unsafe {
                try_read_sensor_output(resolver, 1, |ptr, _capacity| {
                    ptr.write(raw_shape(0, brand.world0()));
                    1
                })
            })
            .unwrap_err();
        assert_eq!(error, Error::InvalidShapeId);

        let out = registry
            .with_output_resolver(|resolver| unsafe {
                try_read_sensor_output(resolver, 1, |ptr, _capacity| {
                    ptr.write(raw_shape(2, brand.world0()));
                    1
                })
            })
            .unwrap();
        let raw = out[0].into_raw();
        assert_eq!(raw.index1, 2);
        assert_eq!(raw.world0, brand.world0());
        assert_eq!(raw.generation, 1);
    }
}