Commit 582d731f authored by Noxim's avatar Noxim
Browse files

Release 0.1.0

parent 8488c446
Pipeline #891 failed with stages
in 0 seconds
[package]
name = "definitive"
version = "0.0.0-alpha.3"
version = "0.1.0"
description = "The definitive and final vector & matrix library for Rust"
authors = ["noxim <aaro.peramaa@gmail.com>"]
homepage = "https://owo.codes/noxim/definitive"
......@@ -16,6 +16,4 @@ edition = "2018"
[features]
default = ["std", "simd"]
std = []
simd = []
[dependencies]
simd = []
\ No newline at end of file
......@@ -7,16 +7,15 @@ impl<T: Add<Output = T>, const N: usize> Add for Vector<T, { N }> {
default fn add(mut self, rhs: Self) -> Self::Output {
// safe as both are owned
self.0.iter_mut().zip(rhs.0.iter()).for_each(|(v, r)| {
*v = unsafe { core::ptr::read(v).add(core::ptr::read(r)) }
});
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(v, r)| *v = unsafe { core::ptr::read(v).add(core::ptr::read(r)) });
self
}
}
impl<T: Add<T, Output = T> + Clone, const N: usize> Add<T>
for Vector<T, { N }>
{
impl<T: Add<T, Output = T> + Clone, const N: usize> Add<T> for Vector<T, { N }> {
type Output = Vector<T, { N }>;
fn add(mut self, rhs: T) -> Self::Output {
......
......@@ -12,9 +12,7 @@ impl<T: AddAssign, const N: usize> AddAssign for Vector<T, { N }> {
}
}
impl<T: AddAssign<T> + Clone, const N: usize> AddAssign<T>
for Vector<T, { N }>
{
impl<T: AddAssign<T> + Clone, const N: usize> AddAssign<T> for Vector<T, { N }> {
fn add_assign(&mut self, rhs: T) {
self.0.iter_mut().for_each(|v| v.add_assign(rhs.clone()));
}
......
......@@ -7,16 +7,15 @@ impl<T: Div<Output = T>, const N: usize> Div for Vector<T, { N }> {
default fn div(mut self, rhs: Self) -> Self::Output {
// safe as both are owned
self.0.iter_mut().zip(rhs.0.iter()).for_each(|(v, r)| {
*v = unsafe { core::ptr::read(v).div(core::ptr::read(r)) }
});
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(v, r)| *v = unsafe { core::ptr::read(v).div(core::ptr::read(r)) });
self
}
}
impl<T: Div<T, Output = T> + Clone, const N: usize> Div<T>
for Vector<T, { N }>
{
impl<T: Div<T, Output = T> + Clone, const N: usize> Div<T> for Vector<T, { N }> {
type Output = Vector<T, { N }>;
fn div(mut self, rhs: T) -> Self::Output {
......@@ -26,3 +25,10 @@ impl<T: Div<T, Output = T> + Clone, const N: usize> Div<T>
self
}
}
#[cfg(test)]
#[test]
fn divide_scalar() {
// rust divides downwards
assert_eq!(Vector::from([2, 1, -5]) / 2, Vector::from([1, 0, -2]));
}
......@@ -12,9 +12,7 @@ impl<T: DivAssign, const N: usize> DivAssign for Vector<T, { N }> {
}
}
impl<T: DivAssign<T> + Clone, const N: usize> DivAssign<T>
for Vector<T, { N }>
{
impl<T: DivAssign<T> + Clone, const N: usize> DivAssign<T> for Vector<T, { N }> {
fn div_assign(&mut self, rhs: T) {
self.0.iter_mut().for_each(|v| v.div_assign(rhs.clone()));
}
......
......@@ -26,12 +26,13 @@
//! let a = Vector::from([2, 3, 1]);
//! let b = Vector::from([8, 0, 0]);
//!
//! let c = a + b;
//! dbg!(a + b * 4);
//! // [34, 3, 1]
//! ```
//!
//! ### `#![no_std]` is supported by disabling the `std` feature
#![feature(const_generics, specialization)]
#![feature(const_generics, specialization, trivial_bounds)]
#![allow(incomplete_features)]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
......@@ -56,7 +57,14 @@ mod sub;
mod sub_assign;
mod traits;
mod vector;
pub use traits::{One, Zero};
pub use traits::{One, Sqrt, Zero};
/// Shorthand for Vector<f32, 2>
pub type Vec2 = Vector<f32, 2>;
/// Shorthand for Vector<f32, 3>
pub type Vec3 = Vector<f32, 3>;
/// Shorthand for Vector<f32, 4>
pub type Vec4 = Vector<f32, 4>;
/// A generic type representing an N dimensional vector
pub struct Vector<T = f32, const N: usize>([T; { N }]);
......@@ -67,19 +75,5 @@ impl<T, const N: usize> From<[T; { N }]> for Vector<T, { N }> {
}
}
// /// ```rust
// /// use definitive::{Matrix, Vector};
// /// let a = Matrix(Vector::from([Vector::from([1.0; 4]); 4]));
// /// let b = Matrix(Vector::from([Vector::from([1.0; 4]); 4]));
// /// let c = a.x( b);
// /// panic!("{:#?}", c);
// /// ```
// #[derive(Debug)]
// pub struct Matrix(pub Vector<Vector<f32, {4}>, {4}>);
// impl Matrix {
// ///
// pub fn x(self, other: Self) -> Self {
// Matrix(self.0 + other.0)
// }
// }
// TODO: Figure out a workaround
// struct Matrix<T, const N: usize, const D: [usize; N]>([T; { D.iter().sum() }]);
......@@ -12,11 +12,14 @@ use crate::Vector;
/// ```rust
/// use definitive::{Vector, vector};
///
/// assert_eq!(vector! {
/// 4,
/// y: 2,
/// z: 3
/// }, Vector::from([0, 2, 3, 0]));
/// assert_eq!(
/// vector! {
/// 4,
/// y: 2,
/// z: 3
/// },
/// Vector::from([0, 2, 3, 0])
/// );
/// ```
#[macro_export]
macro_rules! vector {
......
......@@ -7,16 +7,15 @@ impl<T: Mul<Output = T>, const N: usize> Mul for Vector<T, { N }> {
default fn mul(mut self, rhs: Self) -> Self::Output {
// safe as both are owned
self.0.iter_mut().zip(rhs.0.iter()).for_each(|(v, r)| {
*v = unsafe { core::ptr::read(v).mul(core::ptr::read(r)) }
});
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(v, r)| *v = unsafe { core::ptr::read(v).mul(core::ptr::read(r)) });
self
}
}
impl<T: Mul<T, Output = T> + Clone, const N: usize> Mul<T>
for Vector<T, { N }>
{
impl<T: Mul<T, Output = T> + Clone, const N: usize> Mul<T> for Vector<T, { N }> {
type Output = Vector<T, { N }>;
fn mul(mut self, rhs: T) -> Self::Output {
......
......@@ -12,9 +12,7 @@ impl<T: MulAssign, const N: usize> MulAssign for Vector<T, { N }> {
}
}
impl<T: MulAssign<T> + Clone, const N: usize> MulAssign<T>
for Vector<T, { N }>
{
impl<T: MulAssign<T> + Clone, const N: usize> MulAssign<T> for Vector<T, { N }> {
fn mul_assign(&mut self, rhs: T) {
self.0.iter_mut().for_each(|v| v.mul_assign(rhs.clone()));
}
......
......@@ -7,16 +7,15 @@ impl<T: Rem<Output = T>, const N: usize> Rem for Vector<T, { N }> {
default fn rem(mut self, rhs: Self) -> Self::Output {
// safe as both are owned
self.0.iter_mut().zip(rhs.0.iter()).for_each(|(v, r)| {
*v = unsafe { core::ptr::read(v).rem(core::ptr::read(r)) }
});
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(v, r)| *v = unsafe { core::ptr::read(v).rem(core::ptr::read(r)) });
self
}
}
impl<T: Rem<T, Output = T> + Clone, const N: usize> Rem<T>
for Vector<T, { N }>
{
impl<T: Rem<T, Output = T> + Clone, const N: usize> Rem<T> for Vector<T, { N }> {
type Output = Vector<T, { N }>;
fn rem(mut self, rhs: T) -> Self::Output {
......
......@@ -12,9 +12,7 @@ impl<T: RemAssign, const N: usize> RemAssign for Vector<T, { N }> {
}
}
impl<T: RemAssign<T> + Clone, const N: usize> RemAssign<T>
for Vector<T, { N }>
{
impl<T: RemAssign<T> + Clone, const N: usize> RemAssign<T> for Vector<T, { N }> {
fn rem_assign(&mut self, rhs: T) {
self.0.iter_mut().for_each(|v| v.rem_assign(rhs.clone()));
}
......
......@@ -7,16 +7,15 @@ impl<T: Sub<Output = T>, const N: usize> Sub for Vector<T, { N }> {
default fn sub(mut self, rhs: Self) -> Self::Output {
// safe as both are owned
self.0.iter_mut().zip(rhs.0.iter()).for_each(|(v, r)| {
*v = unsafe { core::ptr::read(v).sub(core::ptr::read(r)) }
});
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(v, r)| *v = unsafe { core::ptr::read(v).sub(core::ptr::read(r)) });
self
}
}
impl<T: Sub<T, Output = T> + Clone, const N: usize> Sub<T>
for Vector<T, { N }>
{
impl<T: Sub<T, Output = T> + Clone, const N: usize> Sub<T> for Vector<T, { N }> {
type Output = Vector<T, { N }>;
fn sub(mut self, rhs: T) -> Self::Output {
......
......@@ -12,9 +12,7 @@ impl<T: SubAssign, const N: usize> SubAssign for Vector<T, { N }> {
}
}
impl<T: SubAssign<T> + Clone, const N: usize> SubAssign<T>
for Vector<T, { N }>
{
impl<T: SubAssign<T> + Clone, const N: usize> SubAssign<T> for Vector<T, { N }> {
fn sub_assign(&mut self, rhs: T) {
self.0.iter_mut().for_each(|v| v.sub_assign(rhs.clone()));
}
......
//! Numeric traits for `ones`, `zeros` and `identity`
//! Numeric traits for `ones`, `zeros`, `identity` and `sqrt`
use crate::Vector;
......@@ -14,6 +14,12 @@ pub trait Zero {
fn zero() -> Self;
}
/// Square root
pub trait Sqrt {
/// Square root of value
fn sqrt(self) -> Self;
}
impl<T: Zero, const N: usize> Zero for Vector<T, { N }> {
fn zero() -> Self {
// so annoying you can't do this (yet?)
......@@ -37,6 +43,18 @@ impl<T: One, const N: usize> One for Vector<T, { N }> {
}
}
impl Sqrt for f32 {
fn sqrt(self) -> Self {
f32::sqrt(self)
}
}
impl Sqrt for f64 {
fn sqrt(self) -> Self {
f64::sqrt(self)
}
}
macro_rules! __impl__trait {
($t:ty) => {
impl One for $t {
......
use core::ops::{Add, Mul};
use core::ops::{Add, Div, Mul};
use crate::{One, Vector, Zero};
use crate::{One, Sqrt, Vector, Zero};
impl<T, const N: usize> Vector<T, { N }> {
/// Create a new vector out of some components
......@@ -15,10 +15,7 @@ impl<T, const N: usize> Vector<T, { N }> {
///
/// See also `resize`, `resize_zero` and `resize_one` for Vector<T, _>'s
/// that have `Default`, `Zero` and `One` implementations, respectively
pub fn resize_with<const M: usize>(
self,
mut fill: impl FnMut() -> T,
) -> Vector<T, { M }> {
pub fn resize_with<const M: usize>(self, mut fill: impl FnMut() -> T) -> Vector<T, { M }> {
let mut inner: [T; { M }] = unsafe { core::mem::zeroed() };
let mut iter = self.0.into_iter();
for value in inner.iter_mut() {
......@@ -52,117 +49,58 @@ impl<T: Zero, const N: usize> Vector<T, { N }> {
}
}
impl<T: Mul<Output = T> + Add<Output = T>, const N: usize> Vector<T, { N }> {
//! # Requires `T: Add + Mul`
impl<T: Mul<Output = T> + Add<Output = T> + Zero, const N: usize> Vector<T, { N }> {
//! # Requires `T: Add + Mul + Zero`
/// Calculate the dot product
///
/// `A1 * B1 + A2 * B2 + ... + An * Bn`
///
/// # Panics
/// This method will panic if the vectors are zero length, as the sum of
/// elements cannot be calculated. Zero length vectors are rare, but for
/// those you can use `dot_checked`
pub fn dot(self, rhs: Self) -> T {
self.dot_checked(rhs)
.expect("Cannot calculate the dot product of a zero length vector")
}
/// Calculate the dot product, or `None` if unable
///
/// In most cases `dot` will suffice, as `None` is only returned with zero
/// length vectors.
pub fn dot_checked(self, rhs: Self) -> Option<T> {
let n = self.mul(rhs);
n.0.into_iter().fold(None, |s: Option<T>, v| {
// we should be able to make this unnecessary, idk why v is &T
let v = unsafe { core::ptr::read(v) };
if let Some(s) = s {
Some(s.add(v))
} else {
Some(v)
}
n.0.into_iter().fold(Zero::zero(), |s, v| {
// TODO: Remove unsafe
s.add(unsafe { core::ptr::read(v) })
})
}
}
impl<T: Mul<Output = T> + Add<Output = T> + Clone, const N: usize>
Vector<T, { N }>
{
//! # Requires `T: Add + Mul + Clone`
// TODO: Remove the clone bound
impl<T: Mul<Output = T> + Add<Output = T> + Clone + Zero, const N: usize> Vector<T, { N }> {
//! # Requires `T: Add + Mul + Clone + Zero`
/// Calculate the length of the vector and square it
///
/// `A1^2 + A2^2 + ... + An^2`
///
/// # Panics
/// This method will panic if the vector is zero length, as the sum of
/// elements cannot be calculated. Zero length vectors are rare, but for
/// those you can use `length2_checked`
pub fn length2(&self) -> T {
self.length2_checked()
.expect("Cannot calculate the dot product of a zero length vector")
}
/// Calculate the squared length of a vector, or `None` if unable
///
/// In most cases `dot` will suffice, as `None` is only returned with zero
/// length vectors.
pub fn length2_checked(&self) -> Option<T> {
self.0.iter().fold(None, |s: Option<T>, v| {
self.0.iter().fold(Zero::zero(), |s, v| {
let v2 = Mul::mul(v.clone(), v.clone());
if let Some(s) = s {
Some(s.add(v2))
} else {
Some(v2)
}
s.add(v2)
})
}
}
#[cfg(feature = "std")]
impl<const N: usize> Vector<f32, { N }> {
/// Calculate the length or magnitude of this vector
///
/// Note: This function requires the standard library
///
/// # Panics
/// This method will panic if the vectors is zero length, as the sum of
/// elements cannot be calculated. Zero length vectors are rare, but for
/// those you can use `length_checked`
pub fn length(&self) -> f32 {
self.length2().sqrt()
}
impl<T: Mul<Output = T> + Add<Output = T> + Clone + Zero + Sqrt, const N: usize> Vector<T, { N }> {
//! # Requires `T: Add + Mul + Clone + Zero + Sqrt`
/// Calculate the length or magnitude of this vector, or `None` if unable
/// Calculate the length/magnitude of the vector
///
/// In most cases `length` will suffice, as `None` is only returned with zero
/// length vectors.
pub fn length_checked(&self) -> Option<f32> {
self.length2_checked().map(|v| v.sqrt())
/// `sqrt(A1^2 + A2^2 + ... + An^2)`
pub fn length(&self) -> T {
self.length2().sqrt()
}
}
#[cfg(feature = "std")]
impl<const N: usize> Vector<f64, { N }> {
/// Calculate the length or magnitude of this vector
///
/// Note: This function requires the standard library
///
/// # Panics
/// This method will panic if the vectors is zero length, as the sum of
/// elements cannot be calculated. Zero length vectors are rare, but for
/// those you can use `length_checked`
pub fn length(&self) -> f64 {
self.length2().sqrt()
}
impl<
T: Mul<Output = T> + Div<Output = T> + Add<Output = T> + Clone + Zero + Sqrt,
const N: usize,
> Vector<T, { N }>
{
//! # Requires `T: Add + Mul + Clone + Zero + Sqrt`
/// Calculate the length or magnitude of this vector, or `None` if unable
///
/// In most cases `length` will suffice, as `None` is only returned with zero
/// length vectors.
pub fn length_checked(&self) -> Option<f64> {
self.length2_checked().map(|v| v.sqrt())
/// Normalize the vector, making its length one
pub fn normalize(self) -> Self {
let length = self.length();
self.div(length)
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment