Created a new math library.

This library will e the math library of the magic game engine.

Currently, it defines basic numerical types that can be used in generic programming
and a set of generic Vector structures.

Tests can be added to the "tests" crate.
This commit is contained in:
Jason Travis Smith 2015-10-04 02:59:26 -04:00
commit 0160780bd1
10 changed files with 571 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
target
Cargo.lock

4
Cargo.toml Normal file
View File

@ -0,0 +1,4 @@
[package]
name = "sigils"
version = "0.1.0"
authors = ["Jason Travis Smith <Jason@CyberMagesLLC.com>"]

29
src/integer.rs Normal file
View File

@ -0,0 +1,29 @@
use super::number::Number;
/// A trait that defines what is required to be considered
/// an Integer. [List of types of numbers][1]
///
/// [1]: https://en.wikipedia.org/wiki/List_of_types_of_numbers
pub trait Integer : Number
{
}
// Create a macro to ease typing and reading.
/// A macro to make implementing the trait easier for all the
/// base integer types in rust.
macro_rules! integer_trait_impl
{
($traitName: ident for $($varType: ty)*) =>
($(
impl $traitName for $varType
{
}
)*)
}
// Implement the trait for the types that are Integers.
integer_trait_impl!(Integer for u8 u16 u32 u64 usize);
integer_trait_impl!(Integer for i8 i16 i32 i64 isize);

13
src/lib.rs Normal file
View File

@ -0,0 +1,13 @@
#![feature(zero_one)]
#![feature(float_from_str_radix)]
mod number;
mod whole;
mod integer;
mod real;
pub mod vector;
pub use self::vector::Vector;

63
src/number.rs Normal file
View File

@ -0,0 +1,63 @@
use std::cmp::PartialEq;
use std::num::{Zero, One};
use std::ops::{Add, Sub, Mul, Div, Rem};
/// A trait that defines what is required to be considered
/// a number.
pub trait Number : Zero + One + Add<Output=Self> + Sub<Output=Self> +
Mul<Output=Self> + Div<Output=Self> + Rem<Output=Self> +
PartialEq + Copy + Clone
{
type StrRadixError;
/// Create a number from a given string and base radix.
fn from_str_radix(src: &str, radix: u32) ->
Result<Self, Self::StrRadixError>;
}
// Create some macros to ease typing and reading.
/// A macro to make implementing the trait easier for all the
/// base integer types in rust.
macro_rules! int_trait_impl
{
($traitName: ident for $($varType: ty)*) =>
($(
impl Number for $varType
{
type StrRadixError = ::std::num::ParseIntError;
fn from_str_radix(src: &str, radix: u32) ->
Result<Self, ::std::num::ParseIntError>
{
<$varType>::from_str_radix(src, radix)
}
}
)*)
}
/// A macro to make implementing the trait easier for all the
/// base float types in rust.
macro_rules! float_trait_impl
{
($traitName: ident for $($varType: ty)*) =>
($(
impl $traitName for $varType
{
type StrRadixError = ::std::num::ParseFloatError;
fn from_str_radix(src: &str, radix: u32) ->
Result<Self, ::std::num::ParseFloatError>
{
<$varType>::from_str_radix(src, radix)
}
}
)*)
}
// Implement the trait for the types that are Numbers.
int_trait_impl!(Number for u8 u16 u32 u64 usize);
int_trait_impl!(Number for i8 i16 i32 i64 isize);
float_trait_impl!(Number for f32 f64);

28
src/real.rs Normal file
View File

@ -0,0 +1,28 @@
use super::number::Number;
/// A trait that defines what is required to be considered
/// a Real number. [List of types of numbers][1]
///
/// [1]: https://en.wikipedia.org/wiki/List_of_types_of_numbers
trait Real : Number
{
}
// Create a macro to ease typing and reading.
/// A macro to make implementing the trait easier for all the
/// base float types in rust.
macro_rules! real_trait_impl
{
($traitName: ident for $($varType: ty)*) =>
($(
impl Real for $varType
{
}
)*)
}
// Implement the trait for the types that are Real numbers.
real_trait_impl!(Real for f32 f64);

388
src/vector.rs Normal file
View File

@ -0,0 +1,388 @@
use std::num::{Zero, One};
use std::ops::{Add, Sub, Mul, Div, Rem};
use super::number::Number;
/// A trait that defines the minimum set of
/// functions a Vector must implement.
pub trait Vector<T> : Clone where T: Number
{
// Creation functions.
/// Create a Vector from a single value.
fn from_value(val: T) -> Self;
/// Create a zero Vector. All components will be set to zero.
fn zero() -> Self
{
Self::from_value(T::zero())
}
/// Create an identity Vector. All components will be set to one.
fn identity() -> Self
{
Self::from_value(T::one())
}
// Scalar operations that result in a new Vector.
/// Add a scalar value to this Vector and return a new Vector.
fn add_scalar(&self, scalar: T) -> Self;
/// Subtract a scalar value from this Vector and return a new Vector.
fn sub_scalar(&self, scalar: T) -> Self;
/// Multiply this Vector by a scalar value and return a new Vector.
fn mul_scalar(&self, scalar: T) -> Self;
/// Divide this Vector by a scalar value and return a new Vector.
fn div_scalar(&self, scalar: T) -> Self;
/// Divide this Vector by a scalar value, take the remainder,
/// and return a new Vector.
fn rem_scalar(&self, scalar: T) -> Self;
// Vector operations that result in a new Vector.
/// Add a Vector to this Vector and return a new Vector.
fn add_vector(&self, vector: &Self) -> Self;
/// Subtract a Vector from this Vector and return a new Vector.
fn sub_vector(&self, vector: &Self) -> Self;
/// Multiply this Vector by a Vector and return a new Vector.
fn mul_vector(&self, vector: &Self) -> Self;
/// Divide this Vector by a Vector and return a new Vector.
fn div_vector(&self, vector: &Self) -> Self;
/// Divide this Vector by a Vector, take the remainder,
/// and return a new Vector.
fn rem_vector(&self, vector: &Self) -> Self;
// Scalar operations that change this Vector.
/// Add a scalar value to this Vector.
fn add_scalar_self(&mut self, scalar: T);
/// Subtract a scalar value from this Vector.
fn sub_scalar_self(&mut self, scalar: T);
/// Multiply this Vector by a scalar value.
fn mul_scalar_self(&mut self, scalar: T);
/// Divide this Vector by a scalar value.
fn div_scalar_self(&mut self, scalar: T);
/// Divide this Vector by a scalar value and take the remainder.
fn rem_scalar_self(&mut self, scalar: T);
// Vector operations that change this Vector.
/// Add a Vector to this Vector.
fn add_vector_self(&mut self, vector: &Self);
/// Subtract a Vector from this Vector.
fn sub_vector_self(&mut self, vector: &Self);
/// Multiply this Vector by a Vector.
fn mul_vector_self(&mut self, vector: &Self);
/// Divide this Vector by a Vector.
fn div_vector_self(&mut self, vector: &Self);
/// Divide this Vector by a Vector and take the remainder.
fn rem_vector_self(&mut self, vector: &Self);
// Basic Vector functions.
/// Get the sum of all the components of the Vector.
fn get_sum(&self) -> T;
/// Get the product of all the components of the Vector.
fn get_product(&self) -> T;
/// Get the dot product between this and another Vector.
fn dot(&self, vector: &Self) -> T
{
self.mul_vector(vector).get_sum()
}
}
// Create a few macros to define the three Vector
// structs: Vector2, Vector3, and Vector4.
/// A macro that will help with adding and
/// multiplying components of a vector.
macro_rules! perform_method_on_components
{
($method: ident, {$x: expr, $y: expr}) =>
{
$x.$method($y)
};
($method: ident, {$x: expr, $y: expr, $z: expr}) =>
{
$x.$method($y).$method($z)
};
($method: ident, {$x: expr, $y: expr, $z: expr, $w: expr}) =>
{
$x.$method($y).$method($z).$method($w)
};
}
/// A macro that will define a binary operation
/// a Vector and its components.
macro_rules! binary_operator_impl
{
($traitName: ident :: $funcName: ident,
$structName: ident {$($field: ident),+}) =>
{
impl<'a, T> $traitName<T> for &'a $structName<T> where T: Number
{
type Output = $structName<T>;
fn $funcName(self, scalar: T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(scalar)),+)
}
}
impl<'a, 'b, T> $traitName<&'a $structName<T>> for &'b $structName<T>
where T: Number
{
type Output = $structName<T>;
fn $funcName(self, vector: &'a $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(vector.$field)),+)
}
}
}
}
/// A macro that defines a Vector structure
/// that implements the Vector trait.
macro_rules! define_vector
{
($structName: ident <$T: ident> {$($field: ident),+}) =>
{
#[derive(PartialEq, Eq, Copy, Clone, Hash)]
pub struct $structName<T> where T: Number
{
$(pub $field: T),+
}
impl<$T> $structName<$T> where T: Number
{
pub fn new($($field: $T),+) -> $structName<$T>
{
$structName {$($field: $field),+}
}
}
impl<T> Vector<T> for $structName<T> where T: Number
{
fn from_value(val: T) -> $structName<T>
{
$structName {$($field: val),+}
}
fn add_scalar(&self, scalar: T) -> $structName<T>
{
self + scalar
}
fn sub_scalar(&self, scalar: T) -> $structName<T>
{
self - scalar
}
fn mul_scalar(&self, scalar: T) -> $structName<T>
{
self * scalar
}
fn div_scalar(&self, scalar: T) -> $structName<T>
{
self / scalar
}
fn rem_scalar(&self, scalar: T) -> $structName<T>
{
self % scalar
}
fn add_vector(&self, vector: &$structName<T>) -> $structName<T>
{
self + vector
}
fn sub_vector(&self, vector: &$structName<T>) -> $structName<T>
{
self - vector
}
fn mul_vector(&self, vector: &$structName<T>) -> $structName<T>
{
self * vector
}
fn div_vector(&self, vector: &$structName<T>) -> $structName<T>
{
self / vector
}
fn rem_vector(&self, vector: &$structName<T>) -> $structName<T>
{
self % vector
}
fn add_scalar_self(&mut self, scalar: T)
{
*self = &*self + scalar;
}
fn sub_scalar_self(&mut self, scalar: T)
{
*self = &*self - scalar;
}
fn mul_scalar_self(&mut self, scalar: T)
{
*self = &*self * scalar;
}
fn div_scalar_self(&mut self, scalar: T)
{
*self = &*self / scalar;
}
fn rem_scalar_self(&mut self, scalar: T)
{
*self = &*self % scalar;
}
fn add_vector_self(&mut self, vector: &$structName<T>)
{
*self = &*self + vector;
}
fn sub_vector_self(&mut self, vector: &$structName<T>)
{
*self = &*self - vector;
}
fn mul_vector_self(&mut self, vector: &$structName<T>)
{
*self = &*self * vector;
}
fn div_vector_self(&mut self, vector: &$structName<T>)
{
*self = &*self / vector;
}
fn rem_vector_self(&mut self, vector: &$structName<T>)
{
*self = &*self % vector;
}
fn get_sum(&self) -> T
{
perform_method_on_components!(add, {$(self.$field),+})
}
fn get_product(&self) -> T
{
perform_method_on_components!(mul, {$(self.$field),+})
}
}
binary_operator_impl!(Add::add, $structName {$($field),+});
binary_operator_impl!(Sub::sub, $structName {$($field),+});
binary_operator_impl!(Mul::mul, $structName {$($field),+});
binary_operator_impl!(Div::div, $structName {$($field),+});
binary_operator_impl!(Rem::rem, $structName {$($field),+});
}
}
// Define the Vector2, Vector3, and Vector4 structures.
define_vector!(Vector2<T> {x, y});
define_vector!(Vector3<T> {x, y, z});
define_vector!(Vector4<T> {x, y, z, w});
// Implements operations specific to the different
// Vector structure sizes.
impl<T> Vector2<T> where T: Number
{
pub fn unit_x() -> Vector2<T>
{
Vector2::new(T::one(), T::zero())
}
pub fn unit_y() -> Vector2<T>
{
Vector2::new(T::zero(), T::one())
}
pub fn perpendicular_dot(&self, vector: &Vector2<T>) -> T
{
(self.x * vector.y) - (self.y * vector.x)
}
}
impl<T> Vector3<T> where T: Number
{
pub fn unit_x() -> Vector3<T>
{
Vector3::new(T::one(), T::zero(), T::zero())
}
pub fn unit_y() -> Vector3<T>
{
Vector3::new(T::zero(), T::one(), T::zero())
}
pub fn unit_z() -> Vector3<T>
{
Vector3::new(T::zero(), T::zero(), T::one())
}
pub fn cross(&self, vector: &Vector3<T>) -> Vector3<T>
{
Vector3::new((self.y * vector.z) - (self.z * vector.y),
(self.z * vector.x) - (self.x * vector.z),
(self.x * vector.y) - (self.y * vector.x))
}
}
impl<T> Vector4<T> where T: Number
{
pub fn unit_x() -> Vector4<T>
{
Vector4::new(T::one(), T::zero(), T::zero(), T::zero())
}
pub fn unit_y() -> Vector4<T>
{
Vector4::new(T::zero(), T::one(), T::zero(), T::zero())
}
pub fn unit_z() -> Vector4<T>
{
Vector4::new(T::zero(), T::zero(), T::one(), T::zero())
}
pub fn unit_w() -> Vector4<T>
{
Vector4::new(T::zero(), T::zero(), T::zero(), T::one())
}
}

28
src/whole.rs Normal file
View File

@ -0,0 +1,28 @@
use super::number::Number;
/// A trait that defines what is required to be considered
/// a Whole number. [List of types of numbers][1]
///
/// [1]: https://en.wikipedia.org/wiki/List_of_types_of_numbers
trait Whole : Number
{
}
// Create a macro to ease typing and reading.
/// A macro to make implementing the trait easier for all the
/// base integer types in rust.
macro_rules! whole_trait_impl
{
($traitName: ident for $($varType: ty)*) =>
($(
impl $traitName for $varType
{
}
)*)
}
// Implement the trait for the types that are Whole numbers.
whole_trait_impl!(Whole for u8 u16 u32 u64 usize);

3
tests/lib.rs Normal file
View File

@ -0,0 +1,3 @@
extern crate sigils;
mod vector;

13
tests/vector.rs Normal file
View File

@ -0,0 +1,13 @@
extern crate sigils;
use sigils::Vector;
#[test]
fn vector_creation()
{
let v: Vector<f32>;
v = Vector::new();
assert_eq!(v.x, 1.0f32);
}