gemath 0.1.0

Type-safe game math with type-level units/spaces, typed angles, and explicit fallible ops (plus optional geometry/collision).
Documentation
//! `gemath` — a small, type-safe math library.
//!
//! The library’s differentiators are:
//! - **Type-level units** and **type-level coordinate spaces** on core math types (e.g. `Vec2<Unit, Space>`).
//! - A clear `no_std` posture (via feature flags).
//! - Typed angles (`Radians` / `Degrees`) and “checked / fallible” APIs where appropriate.
//!
//! ## Getting started
//!
//! ### 1) Vectors, typed angles, and rotation
//!
//! ```rust
//! # #[cfg(feature = "vec2")]
//! # {
//! use gemath::{Degrees, Vec2};
//!
//! let v: Vec2<(), ()> = Vec2::new(1.0, 0.0);
//! let r = v.rotate_deg(Degrees(90.0));
//! assert!((r - Vec2::new(0.0, 1.0)).length() < 1e-5);
//! # }
//! ```
//!
//! ### 2) Units and spaces at the type level
//!
//! ```rust
//! # #[cfg(feature = "vec2")]
//! # {
//! use gemath::{Meters, Vec2, World};
//!
//! // A position in world space, measured in meters.
//! let p: Vec2<Meters, World> = Vec2::new(10.0, 20.0);
//!
//! // Operations preserve the tags.
//! let q: Vec2<Meters, World> = p + Vec2::new(1.0, 2.0);
//! let _ = q;
//! # }
//! ```
//!
//! ### 3) Mat4 TRS composition (translation / rotation / scale)
//!
//! ```rust
//! # #[cfg(all(feature = "mat4", feature = "quat"))]
//! # {
//! use gemath::{Mat4, Quat, Radians, Vec3};
//!
//! let t = Vec3::new(1.0, 2.0, 3.0);
//! let r: Quat<(), ()> = Quat::from_axis_angle_radians(
//!     Vec3::new(0.0, 0.0, 1.0),
//!     Radians(core::f32::consts::FRAC_PI_2),
//! );
//! let s = Vec3::new(2.0, 2.0, 2.0);
//! let m: Mat4<(), ()> = Mat4::from_trs(t, r, s);
//!
//! let p = m.transform_point(Vec3::new(1.0, 0.0, 0.0));
//! // After a 90° rotation around Z and uniform scale, the x-axis point ends up on +Y (plus translation).
//! assert!((p - Vec3::new(1.0, 4.0, 3.0)).length() < 1e-5);
//! # }
//! ```
//!
//! ### 4) Structured raycast hits (representative example)
//!
//! ```rust
//! # #[cfg(feature = "collision")]
//! # {
//! use gemath::{ray2_circle_cast, Circle, Ray2, Vec2};
//!
//! let circle: Circle<(), ()> = Circle::new(Vec2::new(0.0, 0.0), 1.0);
//! let ray: Ray2<(), ()> = Ray2::new(Vec2::new(-2.0, 0.0), Vec2::new(1.0, 0.0));
//! let hit = ray2_circle_cast(ray, circle).unwrap();
//! assert!((hit.t - 1.0).abs() < 1e-6);
//! assert!((hit.point - Vec2::new(-1.0, 0.0)).length() < 1e-6);
//! assert!((hit.normal - Vec2::new(-1.0, 0.0)).length() < 1e-6);
//! # }
//! ```
//!
//! ### 5) Allocation-backed primitives behind features (Polygon2)
//!
//! ```rust
//! # #[cfg(all(feature = "polygon2", any(feature = "std", feature = "alloc")))]
//! # {
//! use gemath::{Polygon2, Vec2};
//!
//! let poly: Polygon2<(), ()> = Polygon2::new(vec![
//!     Vec2::new(0.0, 0.0),
//!     Vec2::new(1.0, 0.0),
//!     Vec2::new(1.0, 1.0),
//!     Vec2::new(0.0, 1.0),
//! ]);
//! assert!(poly.contains_point(Vec2::new(0.5, 0.5)));
//! # }
//! ```
//!
//! ## Feature docs
//! - Build/test matrix: see `docs/DEVELOPMENT.md`
//! - Feature dependency graph / minimal builds: see `docs/FEATURES.md`
//!
//! ## Cargo features
//! - `serde`: Enables `serde::Serialize` / `serde::Deserialize` for core types.
//! - `std` (default): Use Rust standard library.
//! - `libm`: Use the `libm` crate for floating-point math when building without `std`.
//! - `alloc`: Enables allocation-backed helpers (e.g. `Vec` conversions) when building without `std`.
//! - `math`: Internal capability used by `std`/`libm` builds (float math backend).
//!
//! ## Scalar type / precision
//! Core types are currently `f32`-based. The public alias [`Real`] documents the chosen scalar.
//!
//! ## “No-Std / No-Alloc / No-Macro” (precise)
//! - **No-Std**: Disable default features. In `no_std` mode, floating-point math requires `libm`.
//! - **No-Alloc**: In `no_std` mode, allocation is opt-in via the `alloc` feature. Modules that require allocation are gated accordingly (e.g. `spatial`).
//! - **No-Macro**: The *minimal* `no_std` build (`--no-default-features --features libm`) does not require procedural macros. Enabling `serde` uses `serde_derive` (proc macros) by design.

#![cfg_attr(not(feature = "std"), no_std)]

// In `no_std` builds, `Vec` lives in `alloc` (if the target provides an allocator).
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;

// Allocation-backed modules must be explicit about their requirements.
#[cfg(all(feature = "polygon2", not(any(feature = "std", feature = "alloc"))))]
compile_error!("feature \"polygon2\" requires either \"std\" (default) or \"alloc\" (for no_std builds).");

#[cfg(feature = "aabb2")]
pub mod aabb2;
#[cfg(feature = "aabb3")]
pub mod aabb3;
#[cfg(feature = "math")]
pub mod math;
#[cfg(feature = "math")]
pub mod numeric;
pub mod markers;
#[cfg(feature = "half_float")]
pub mod half_float;
#[cfg(feature = "mat2")]
pub mod mat2;
#[cfg(feature = "mat3")]
pub mod mat3;
#[cfg(feature = "mat4")]
pub mod mat4;
#[cfg(feature = "quat")]
pub mod quat;
#[cfg(feature = "rect2")]
pub mod rect2;
#[cfg(feature = "rect3")]
pub mod rect3;
#[cfg(feature = "scalar")]
pub mod scalar;
#[cfg(feature = "unit_vec")]
pub mod unit_vec;
#[cfg(feature = "vec2")]
pub mod vec2;
#[cfg(feature = "vec3")]
pub mod vec3;
#[cfg(feature = "vec4")]
pub mod vec4;
#[cfg(feature = "angle")]
pub mod angle;
#[cfg(feature = "geometry")]
pub mod geometry;
#[cfg(feature = "collision")]
pub mod collision;
#[cfg(all(feature = "polygon2", any(feature = "std", feature = "alloc")))]
pub mod polygon2;
#[cfg(all(feature = "spatial", any(feature = "std", feature = "alloc")))]
#[path = "spatial.rs"]
pub mod spatial;

#[cfg(feature = "mint")]
mod mint_conv;

#[cfg(feature = "aabb2")]
pub use aabb2::Aabb2;
#[cfg(feature = "aabb3")]
pub use aabb3::Aabb3;
pub use markers::{Local, Meters, Pixels, Screen, World};

/// The crate’s chosen scalar type.
///
/// `gemath` is currently **`f32`-only**; this alias exists so documentation and downstream code
/// can consistently refer to the scalar type.
pub type Real = f32;
#[cfg(feature = "unit_vec")]
pub use unit_vec::{UnitVec2, UnitVec3, UnitVec4};

#[cfg(feature = "half_float")]
pub use half_float::{Half, f16s_from_half_array, f32s_from_half_array, halfs_from_f16_array, halfs_from_f32_array};

// Slice-to-Vec helpers require allocation (`std` or `alloc`).
#[cfg(any(feature = "std", feature = "alloc"))]
#[cfg(feature = "half_float")]
pub use half_float::{
    f16s_from_half_slice,
    f32s_from_half_slice,
    halfs_from_f16_slice,
    halfs_from_f32_slice,
};

#[cfg(feature = "mat2")]
pub use mat2::Mat2;
#[cfg(feature = "mat3")]
pub use mat3::Mat3;
#[cfg(feature = "mat4")]
pub use mat4::Mat4;
#[cfg(feature = "quat")]
pub use quat::Quat;
#[cfg(feature = "rect2")]
pub use rect2::Rect2;
#[cfg(feature = "rect3")]
pub use rect3::Rect3;

#[cfg(feature = "scalar")]
pub use scalar::{abs, approx_eq, clamp, is_finite, is_nan, max, min, sign, to_degrees, to_radians};

#[cfg(feature = "math")]
pub use numeric::GemathFloat;

#[cfg(feature = "vec2")]
pub use vec2::Vec2;
#[cfg(feature = "vec3")]
pub use vec3::Vec3;
#[cfg(feature = "vec4")]
pub use vec4::Vec4;

#[cfg(feature = "angle")]
pub use angle::{Degrees, Radians};

#[cfg(feature = "geometry")]
pub use geometry::{Capsule2, Capsule3, Circle, Obb2, Obb3, Plane, Ray2, Ray3, Segment2, Segment3, Sphere};

#[cfg(all(feature = "polygon2", any(feature = "std", feature = "alloc")))]
pub use polygon2::Polygon2;

#[cfg(feature = "collision")]
pub use collision::{
    circle_aabb2_intersects,
    circle_rect2_intersects,
    ray2_circle_cast,
    ray2_circle_intersect,
    ray3_sphere_cast,
    ray3_sphere_intersect,
    RayHit2,
    RayHit3,
    segment2_circle_intersects,
    segment2_intersection_point,
    segment2_intersects,
    segment3_sphere_intersects,
    sphere_aabb3_intersects,
    sphere_rect3_intersects,
};

#[cfg(all(feature = "spatial", any(feature = "std", feature = "alloc")))]
pub use spatial::{Bvh3, Quadtree2, UniformGrid2};