Skip to content

Commit

Permalink
vector! and matrix! (#4)
Browse files Browse the repository at this point in the history
* Implement matrix! and vector! macros and backing functions.

* Fix breakage caused by merge.
  • Loading branch information
EkardNT authored and maplant committed Jul 16, 2019
1 parent 480c98d commit 50c337a
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 1 deletion.
180 changes: 179 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,35 @@ pub fn vec4<T>(x: T, y: T, z: T, w: T) -> Vector4<T> {
/// 5-element vector.
pub type Vector5<T> = Vector<T, 5>;

/// Construct a new vector of any size.
///
/// ```
/// # use aljabar::*;
/// let v: Vector<u32, 0> = vector([]);
/// let v = vector([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
/// let v = vector([true, false, false, true]);
/// ```
pub fn vector<T, const N: usize>(elements: [T; N]) -> Vector<T, {N}> {
Vector(elements)
}

/// Construct a new vector of any size.
///
/// ```
/// # use aljabar::*;
/// let v: Vector<u32, 0> = vector![];
/// let v = vector![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
/// let v = vector![true, false, false, true];
/// ```
#[macro_export]
macro_rules! vector {
( $($elem:expr),* $(,)? ) => {
$crate::vector([
$($elem),*
])
}
}

impl<T, const N: usize> From<[T; N]> for Vector<T, {N}> {
fn from(array: [T; N]) -> Self {
Vector::<T, {N}>(array)
Expand Down Expand Up @@ -1101,7 +1130,87 @@ impl<T, const N: usize, const M: usize> From<[Vector<T, {N}>; {M}]> for Matrix<T
}
}

/// Returns a 1-by-1 square matrix.
/// Construct a matrix of any size. The matrix is specified in row-major order,
/// but this function converts it to aljabar's native column-major order.
///
/// ```ignore
/// # NOTE: This code fails to compile in a doc test, although it works fine in a
/// # regular unit test.
/// # use aljabar::*;
/// // `matrix` allows you to create a matrix using natural writing order (row-major).
/// let m1: Matrix<u32, 4, 3> = matrix([
/// [0, 1, 2],
/// [3, 4, 5],
/// [6, 7, 8],
/// [9, 0, 1],
/// ]);
///
/// // The equivalent code using the From implementation is below. Note the From
/// // usage requires you to specify the entries in column-major order, and create
/// // the sub-Vectors explicitly.
/// let m2: Matrix<u32, 4, 3> = Matrix::<u32, 4, 3>::from([
/// Vector::<u32, 4>::from([0, 3, 6, 9]),
/// Vector::<u32, 4>::from([1, 4, 7, 0]),
/// Vector::<u32, 4>::from([2, 5, 8, 1]),
/// ]);
///
/// assert_eq!(m1, m2);
/// ```
pub fn matrix<T: Clone, const N: usize, const M: usize>(rows: [[T; M]; N]) -> Matrix<T, {N}, {M}> {
unsafe {
// Need to swap from row-major to column-major.
let mut columns: MaybeUninit<[Vector<T, {N}>; {M}]> = MaybeUninit::uninit();
let columnp: *mut Vector<T, {N}> = mem::transmute(columns.as_mut_ptr());
for column_index in 0..M {
let mut column: MaybeUninit<Vector<T, {N}>> = MaybeUninit::uninit();
let entryp: *mut T = mem::transmute(column.as_mut_ptr());
for row_index in 0..N {
entryp.add(row_index).write(rows[row_index][column_index].clone());
}
columnp.add(column_index).write(column.assume_init());
}
Matrix(columns.assume_init())
}
}

/// Construct a matrix of any size. The matrix is specified in row-major order,
/// but this function converts it to aljabar's native column-major order.
///
/// ```ignore
/// # NOTE: This code fails to compile in a doc test, although it works fine in a
/// # regular unit test.
/// # use aljabar::*;
/// // `matrix` allows you to create a matrix using natural writing order (row-major).
/// let m1: Matrix<u32, 4, 3> = matrix![
/// [0, 1, 2],
/// [3, 4, 5],
/// [6, 7, 8],
/// [9, 0, 1],
/// ];
///
/// // The equivalent code using the From implementation is below. Note the From
/// // usage requires you to specify the entries in column-major order, and create
/// // the sub-Vectors explicitly.
/// let m2: Matrix<u32, 4, 3> = Matrix::<u32, 4, 3>::from([
/// Vector::<u32, 4>::from([0, 3, 6, 9]),
/// Vector::<u32, 4>::from([1, 4, 7, 0]),
/// Vector::<u32, 4>::from([2, 5, 8, 1]),
/// ]);
///
/// assert_eq!(m1, m2);
/// ```
#[macro_export]
macro_rules! matrix {
( $($rows:expr),* $(,)? ) => {
$crate::matrix([
$($rows),*
])
}
}

/// Returns, uh, a 1-by-1 square matrix.
///
/// I mean, I use it for testing, so I think it's kind of cool.
pub fn mat1x1<T>(
x00: T,
) -> Mat1x1<T> {
Expand Down Expand Up @@ -1955,6 +2064,75 @@ mod tests {
}

#[test]
fn vector_constructor() {
let v: Vector<f32, 0> = vector([]);
assert!(v.is_empty());

let v = vector([1]);
assert_eq!(1, v[0]);

let v = vector([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
for i in 0..10 {
assert_eq!(i + 1, v[i]);
}
}

#[test]
fn vector_macro_constructor() {
let v: Vector<f32, 0> = vector![];
assert!(v.is_empty());

let v = vector![1];
assert_eq!(1, v[0]);

let v = vector![1, 2, 3, 4, 5, 6, 7, 8, 9, 10,];
for i in 0..10 {
assert_eq!(i + 1, v[i]);
}
}

#[test]
fn matrix_constructor() {
let m: Matrix<f32, 0, 0> = matrix([]);
assert!(m.is_empty());

let m = matrix([
[1]
]);
assert_eq!(1, m[0][0]);

let m = matrix([
[1, 2],
[3, 4],
[5, 6],
]);
assert_eq!(m, Matrix::<u32, 3, 2>::from([
Vector::<u32, 3>::from([1, 3, 5]),
Vector::<u32, 3>::from([2, 4, 6])
]));
}

#[test]
fn matrix_macro_constructor() {
let m: Matrix<f32, 0, 0> = matrix![];
assert!(m.is_empty());

let m = matrix![
[1]
];
assert_eq!(1, m[0][0]);

let m = matrix![
[1, 2],
[3, 4],
[5, 6],
];
assert_eq!(m, Matrix::<u32, 3, 2>::from([
Vector::<u32, 3>::from([1, 3, 5]),
Vector::<u32, 3>::from([2, 4, 6])
]));
}

fn test_swizzle() {
let v: Vector<f32, 1> = Vector::<f32, 1>::from([1.0]);
assert_eq!(1.0, v.x());
Expand Down
16 changes: 16 additions & 0 deletions tests/macro_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
extern crate aljabar;

use aljabar::{matrix, vector};

#[test]
fn can_use_vector_macro_outside_aljabar() {
let _ = vector![1, 2, 3, 4, 5, 6];
}

#[test]
fn can_use_matrix_macro_outside_aljabar() {
let _ = matrix![
[1, 2, 3],
[4, 5, 6],
];
}

0 comments on commit 50c337a

Please sign in to comment.