boxdd 0.6.0

Safe, ergonomic Rust bindings for Box2D v3
Documentation
use super::*;
use crate::world::{BodyCall, OwnerCreation};

fn create_shape<G, R>(
    creation: OwnerCreation<'_>,
    body: BodyCall<'_>,
    def: &ShapeDef,
    geometry: &G,
    validate_geometry: impl FnOnce(&G) -> Result<()>,
    into_raw: impl FnOnce(&G) -> R,
    create_raw: impl FnOnce(ffi::b2BodyId, &ffi::b2ShapeDef, &R) -> ffi::b2ShapeId,
) -> Result<ShapeId> {
    if let Err(error) = check_shape_def_valid(def) {
        return creation.abort(error);
    }
    if let Err(error) = validate_geometry(geometry) {
        return creation.abort(error);
    }
    let pending = match body.reserve_shape_creation() {
        Ok(pending) => pending,
        Err(error) => return creation.abort(error),
    };
    let raw = into_raw(geometry);
    let prepared = def.prepare();
    let raw_id = create_raw(body.id().into_raw(), &prepared, &raw);
    let mut native = match body.claim_created_shape(raw_id, def.updates_body_mass()) {
        Ok(native) => native,
        Err(error) => return creation.abort(error),
    };
    let bound = match body.bind_created_shape(pending, raw_id) {
        Ok(bound) => bound,
        Err(error) => return creation.abort(error),
    };
    creation.finish(|| {
        let id = bound.publish();
        native.commit();
        id
    })
}

macro_rules! shape_creator {
    ($name:ident, $geometry:ty, $validate:path, $create:path) => {
        pub(crate) fn $name(
            creation: OwnerCreation<'_>,
            body: BodyCall<'_>,
            def: &ShapeDef,
            geometry: &$geometry,
        ) -> Result<ShapeId> {
            create_shape(
                creation,
                body,
                def,
                geometry,
                $validate,
                |geometry| geometry.into_raw(),
                |body, def, raw| unsafe { $create(body, def, raw) },
            )
        }
    };
}

shape_creator!(
    create_segment_shape_for_body,
    Segment,
    check_segment_geometry_valid,
    ffi::b2CreateSegmentShape
);
shape_creator!(
    create_chain_segment_shape_for_body,
    ChainSegment,
    check_chain_segment_geometry_valid,
    ffi::b2CreateChainSegmentShape
);
shape_creator!(
    create_capsule_shape_for_body,
    Capsule,
    check_capsule_geometry_valid,
    ffi::b2CreateCapsuleShape
);
shape_creator!(
    create_polygon_shape_for_body,
    Polygon,
    check_polygon_geometry_valid,
    ffi::b2CreatePolygonShape
);
shape_creator!(
    create_circle_shape_for_body,
    Circle,
    check_circle_geometry_valid,
    ffi::b2CreateCircleShape
);