46 Commits

Author SHA1 Message Date
14cec421e0 fix test 2024-09-09 15:33:10 -07:00
fb9228b7fd silence warning 2024-09-09 15:33:07 -07:00
3f0900b0ec ratio stuff 2024-09-09 15:25:01 -07:00
658c73a033 div op 2024-09-09 15:25:01 -07:00
b98eba27e5 wide operators 2024-09-09 15:25:01 -07:00
503f5b6d22 comment impl zones 2024-09-09 15:25:01 -07:00
f22cd653df wide-mul is a crate feature
here goes another bottom-up rewrite
2024-09-09 15:25:01 -07:00
8ee6204a42 invent wide_div + test 2024-09-09 15:24:49 -07:00
803f1bea9e extract trait impls into named functions + fix spelling 2024-09-09 15:24:49 -07:00
62419e94e1 consistency 2024-09-09 14:14:48 -07:00
d3c4d530b6 refactor macros, move things around 2024-09-09 14:14:48 -07:00
898407a0e9 matrix and vector extend functions 2024-09-06 13:24:03 -07:00
66186c7354 doc 2024-09-06 13:03:55 -07:00
36c769346c use inline const constructor because it's a little bit prettier 2024-09-06 11:44:43 -07:00
5f2bec75f5 enable matrix mul test 2024-09-06 11:38:29 -07:00
7a9aaf9fe0 matrix mul 2024-09-06 11:38:22 -07:00
9ad90cea2e fix tests 2024-09-06 11:25:51 -07:00
f2fec0b3b9 implement a bunch of fixed wide stuff 2024-09-06 11:25:46 -07:00
dae72d73d5 convert to row-major 2024-09-06 10:52:17 -07:00
4a1eff40da matrix multiplication ascii art 2024-09-06 10:44:30 -07:00
d5bd82761a fix dot test 2024-09-06 10:36:34 -07:00
5cad8637cd tweak dot 2024-09-06 10:36:24 -07:00
607706ee2a nope 2024-09-05 17:56:09 -07:00
2312ee27b7 test vector and matrix (TODO: Debug trait) 2024-09-05 17:56:09 -07:00
4d2aa0b2c8 is this better? 2024-09-05 17:44:44 -07:00
34450d6a13 matrix multiplication 2024-09-05 17:37:38 -07:00
1a6ece1312 epic const generic array transpose
verified that this loop unrolls on compiler explorer
2024-09-05 17:36:45 -07:00
e95f675e91 test named fields 2024-09-05 16:56:59 -07:00
504ff37c47 write a test 2024-09-05 16:45:44 -07:00
41cdd03b1b wip fixed wide 2024-09-05 16:32:19 -07:00
e375173625 keep generic operators and only implement i64 convenience operator 2024-09-05 16:18:13 -07:00
488a6b6496 fix vector bool code 2024-09-05 16:08:53 -07:00
5cdd2c3ee1 must be less generic to avoid conflict with convenience operators 2024-09-05 16:05:47 -07:00
a0da6873c1 vector operators 2024-09-05 15:56:44 -07:00
345d5737a2 more generic Neg operator 2024-09-05 15:56:35 -07:00
f4d28dd3c3 use derive macros 2024-09-05 15:43:26 -07:00
c362081003 implement a bunch of stuff 2024-09-05 15:43:26 -07:00
990a923463 fixup tests 2024-09-05 13:53:03 -07:00
56b781fcb8 we build 2024-09-05 13:52:54 -07:00
e026f6efed wip 2024-09-05 13:36:38 -07:00
e475da5fb4 put that back 2024-09-05 13:16:02 -07:00
c3026c67e9 delete everything and start over 2024-09-05 12:49:20 -07:00
103697fbdd matrix: test det + adjugate 2024-09-04 13:55:11 -07:00
cf17460b77 special case 3d vectors and matrices 2024-09-04 13:47:50 -07:00
823a05c101 matrix: directly implement dot product to avoid a copy 2024-09-04 12:11:52 -07:00
e5f95b97ce matrix: macro mat mul 2024-09-04 12:11:52 -07:00
17 changed files with 834 additions and 775 deletions

View File

@@ -4,8 +4,9 @@ version = "0.1.0"
edition = "2021"
[features]
default=["zeroes"]
default=["zeroes","wide-mul"]
ratio=[]
wide-mul=[]
zeroes=["ratio","dep:arrayvec"]
[dependencies]

View File

@@ -1,6 +1,7 @@
use bnum::{BInt,cast::As};
#[derive(Clone,Copy,Debug,Hash)]
/// A Fixed point number for which multiply operations widen the bits in the output. (when the wide-mul feature is enabled)
/// N is the number of u64s to use
/// F is the number of fractional bits (always N*32 lol)
pub struct Fixed<const N:usize,const F:usize>{
@@ -70,14 +71,28 @@ impl<const N:usize,const F:usize> std::ops::Neg for Fixed<N,F>{
Self::from_bits(self.bits.neg())
}
}
impl<const N:usize,const F:usize> std::iter::Sum for Fixed<N,F>{
fn sum<I:Iterator<Item=Self>>(iter:I)->Self{
let mut sum=Self::ZERO;
for elem in iter{
sum+=elem;
}
sum
}
}
macro_rules! impl_additive_operator {
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
impl<const N:usize,const F:usize> $struct<N,F>{
#[inline]
pub const fn $method(self, other: Self) -> Self {
Self::from_bits(self.bits.$method(other.bits))
}
}
impl<const N:usize,const F:usize> core::ops::$trait for $struct<N,F>{
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
Self::from_bits(self.bits.$method(other.bits))
self.$method(other)
}
}
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
@@ -85,7 +100,6 @@ macro_rules! impl_additive_operator {
BInt::<N>:From<U>,
{
type Output = $output;
fn $method(self, other: U) -> Self::Output {
Self::from_bits(self.bits.$method(BInt::<N>::from(other).shl(F as u32)))
}
@@ -104,7 +118,7 @@ macro_rules! impl_additive_assign_operator {
BInt::<N>:From<U>,
{
fn $method(&mut self, other: U) {
self.bits.$method(BInt::<N>::from(other)<<F as u32);
self.bits.$method(BInt::<N>::from(other).shl(F as u32));
}
}
};
@@ -126,56 +140,69 @@ impl_additive_operator!( Fixed, BitOr, bitor, Self );
impl_additive_assign_operator!( Fixed, BitXorAssign, bitxor_assign );
impl_additive_operator!( Fixed, BitXor, bitxor, Self );
macro_rules! impl_multiply_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
// non-wide operators. The result is the same width as the inputs.
// This macro is not used in the default configuration.
#[allow(unused_macros)]
macro_rules! impl_multiplicative_operator_not_const_generic {
( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => {
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
//this can be done better but that is a job for later
paste::item!{
self.[<fixed_ $method>](other)
}
}
}
};
}
macro_rules! impl_multiplicative_assign_operator_not_const_generic {
( ($struct: ident, $trait: ident, $method: ident, $non_assign_method: ident ), $width:expr ) => {
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
fn $method(&mut self, other: Self) {
paste::item!{
*self=self.[<fixed_ $non_assign_method>](other);
}
}
}
};
}
macro_rules! impl_multiply_operator_not_const_generic {
( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => {
impl<const F:usize> $struct<$width,F>{
paste::item!{
#[inline]
pub fn [<fixed_ $method>](self, other: Self) -> Self {
let lhs=self.bits.as_::<BInt::<{$width*2}>>();
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
Self::from_bits(lhs.mul(rhs).shr(F as u32).as_())
}
}
};
}
macro_rules! impl_multiply_assign_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
fn $method(&mut self, other: Self) {
self.bits.$method(other.bits);
}
}
};
#[cfg(not(feature="wide-mul"))]
impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width);
}
}
macro_rules! impl_divide_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
//this can be done better but that is a job for later
macro_rules! impl_divide_operator_not_const_generic {
( ($struct: ident, $trait: ident, $method: ident, $output: ty ), $width:expr ) => {
impl<const F:usize> $struct<$width,F>{
paste::item!{
#[inline]
pub fn [<fixed_ $method>](self, other: Self) -> Self {
//this only needs to be $width+F as u32/64+1 but MUH CONST GENERICS!!!!!
let lhs=self.bits.as_::<BInt::<{$width*2}>>().shl(F as u32);
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
Self::from_bits(lhs.div(rhs).as_())
}
}
};
}
macro_rules! impl_divide_assign_operator_const {
( $width:expr, $struct: ident, $trait: ident, $method: ident ) => {
impl<const F:usize> core::ops::$trait for $struct<$width,F>{
fn $method(&mut self, other: Self) {
self.bits.$method(other.bits);
}
}
#[cfg(all(not(feature="wide-mul"),not(feature="ratio")))]
impl_multiplicative_operator_not_const_generic!(($struct, $trait, $method, $output ), $width);
};
}
macro_rules! impl_multiplicatave_operator {
macro_rules! impl_multiplicative_operator {
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
where
@@ -189,7 +216,7 @@ macro_rules! impl_multiplicatave_operator {
}
};
}
macro_rules! impl_multiplicatave_assign_operator {
macro_rules! impl_multiplicative_assign_operator {
( $struct: ident, $trait: ident, $method: ident ) => {
impl<const N:usize,const F:usize,U> core::ops::$trait<U> for $struct<N,F>
where
@@ -202,55 +229,41 @@ macro_rules! impl_multiplicatave_assign_operator {
};
}
macro_rules! impl_operator_16 {
( $macro: ident, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
$macro!(1,$struct,$trait,$method,$output);
$macro!(2,$struct,$trait,$method,$output);
$macro!(3,$struct,$trait,$method,$output);
$macro!(4,$struct,$trait,$method,$output);
$macro!(5,$struct,$trait,$method,$output);
$macro!(6,$struct,$trait,$method,$output);
$macro!(7,$struct,$trait,$method,$output);
$macro!(8,$struct,$trait,$method,$output);
$macro!(9,$struct,$trait,$method,$output);
$macro!(10,$struct,$trait,$method,$output);
$macro!(11,$struct,$trait,$method,$output);
$macro!(12,$struct,$trait,$method,$output);
$macro!(13,$struct,$trait,$method,$output);
$macro!(14,$struct,$trait,$method,$output);
$macro!(15,$struct,$trait,$method,$output);
$macro!(16,$struct,$trait,$method,$output);
}
macro_rules! macro_repeated{
(
$macro:ident,
$any:tt,
$($repeated:tt),*
)=>{
$(
$macro!($any, $repeated);
)*
};
}
macro_rules! impl_assign_operator_16 {
( $macro: ident, $struct: ident, $trait: ident, $method: ident ) => {
$macro!(1,$struct,$trait,$method);
$macro!(2,$struct,$trait,$method);
$macro!(3,$struct,$trait,$method);
$macro!(4,$struct,$trait,$method);
$macro!(5,$struct,$trait,$method);
$macro!(6,$struct,$trait,$method);
$macro!(7,$struct,$trait,$method);
$macro!(8,$struct,$trait,$method);
$macro!(9,$struct,$trait,$method);
$macro!(10,$struct,$trait,$method);
$macro!(11,$struct,$trait,$method);
$macro!(12,$struct,$trait,$method);
$macro!(13,$struct,$trait,$method);
$macro!(14,$struct,$trait,$method);
$macro!(15,$struct,$trait,$method);
$macro!(16,$struct,$trait,$method);
macro_rules! macro_16 {
( $macro: ident, $any:tt ) => {
macro_repeated!($macro,$any,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
}
}
impl_assign_operator_16!( impl_multiply_assign_operator_const, Fixed, MulAssign, mul_assign );
impl_operator_16!( impl_multiply_operator_const, Fixed, Mul, mul, Self );
impl_assign_operator_16!( impl_divide_assign_operator_const, Fixed, DivAssign, div_assign );
impl_operator_16!( impl_divide_operator_const, Fixed, Div, div, Self );
impl_multiplicatave_assign_operator!( Fixed, MulAssign, mul_assign );
impl_multiplicatave_operator!( Fixed, Mul, mul, Self );
impl_multiplicatave_assign_operator!( Fixed, DivAssign, div_assign );
impl_multiplicatave_operator!( Fixed, Div, div, Self );
macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, MulAssign, mul_assign, mul) );
macro_16!( impl_multiply_operator_not_const_generic, (Fixed, Mul, mul, Self) );
macro_16!( impl_multiplicative_assign_operator_not_const_generic, (Fixed, DivAssign, div_assign, div) );
macro_16!( impl_divide_operator_not_const_generic, (Fixed, Div, div, Self) );
impl_multiplicative_assign_operator!( Fixed, MulAssign, mul_assign );
impl_multiplicative_operator!( Fixed, Mul, mul, Self );
impl_multiplicative_assign_operator!( Fixed, DivAssign, div_assign );
impl_multiplicative_operator!( Fixed, Div, div, Self );
#[cfg(feature="ratio")]
impl<const LHS_N:usize,const LHS_F:usize,const RHS_N:usize,const RHS_F:usize> core::ops::Div<Fixed<RHS_N,RHS_F>> for Fixed<LHS_N,LHS_F>{
type Output=crate::ratio::Ratio<Fixed<LHS_N,LHS_F>,Fixed<RHS_N,RHS_F>>;
fn div(self, other: Fixed<RHS_N,RHS_F>)->Self::Output{
crate::ratio::Ratio::new(self,other)
}
}
// wide operators. The result width is the sum of the input widths, i.e. none of the multiplication
macro_rules! impl_shift_operator {
( $struct: ident, $trait: ident, $method: ident, $output: ty ) => {
@@ -277,40 +290,78 @@ impl_shift_operator!( Fixed, Shl, shl, Self );
impl_shift_assign_operator!( Fixed, ShrAssign, shr_assign );
impl_shift_operator!( Fixed, Shr, shr, Self );
macro_rules! impl_wide_operators{
($lhs:expr,$rhs:expr)=>{
impl core::ops::Mul<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>;
fn mul(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{
paste::item!{
self.[<wide_mul_ $lhs _ $rhs>](other)
}
}
}
#[cfg(not(feature="ratio"))]
impl core::ops::Div<Fixed<$rhs,{$rhs*32}>> for Fixed<$lhs,{$lhs*32}>{
type Output=Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>;
fn div(self, other: Fixed<$rhs,{$rhs*32}>)->Self::Output{
paste::item!{
self.[<wide_div_ $lhs _ $rhs>](other)
}
}
}
}
}
// WIDE MUL: multiply into a wider type
// let a = I32F32::ONE;
// let b:I64F64 = a.wide_mul(a);
macro_rules! impl_wide_mul{
($lhs:expr,$rhs:expr)=>{
macro_rules! impl_wide_not_const_generic{
(
(),
($lhs:expr,$rhs:expr)
)=>{
impl Fixed<$lhs,{$lhs*32}>
{
paste::item!{
pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
Fixed::from_bits(self.bits.as_::<BInt<{$lhs+$rhs}>>()*rhs.bits.as_::<BInt<{$lhs+$rhs}>>())
let lhs=self.bits.as_::<BInt<{$lhs+$rhs}>>();
let rhs=rhs.bits.as_::<BInt<{$lhs+$rhs}>>();
Fixed::from_bits(lhs*rhs)
}
/// This operation cannot represent the fraction exactly,
/// but it shapes the output to have precision for the
/// largest and smallest possible fractions.
pub fn [<wide_div_ $lhs _ $rhs>](self,rhs:Fixed<$rhs,{$rhs*32}>)->Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
// (lhs/2^LHS_FRAC)/(rhs/2^RHS_FRAC)
let lhs=self.bits.as_::<BInt<{$lhs+$rhs}>>().shl($rhs*64);
let rhs=rhs.bits.as_::<BInt<{$lhs+$rhs}>>();
Fixed::from_bits(lhs/rhs)
}
}
}
};
}
macro_rules! impl_wide_mul_all{
($(($x:expr, $y:expr)),*)=>{
$(
impl_wide_mul!($x, $y);
)*
#[cfg(feature="wide-mul")]
impl_wide_operators!($lhs,$rhs);
};
}
//const generics sidestepped wahoo
impl_wide_mul_all!(
(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),
(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),
(1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),(8,3),
(1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),(8,4),
(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),(8,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6),(8,6),
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8)
macro_repeated!(
impl_wide_not_const_generic,(),
(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,1),(11,1),(12,1),(13,1),(14,1),(15,1),
(1,2),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),
(1,3),(2,3),(3,3),(4,3),(5,3),(6,3),(7,3),(8,3),(9,3),(10,3),(11,3),(12,3),(13,3),
(1,4),(2,4),(3,4),(4,4),(5,4),(6,4),(7,4),(8,4),(9,4),(10,4),(11,4),(12,4),
(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5),(8,5),(9,5),(10,5),(11,5),
(1,6),(2,6),(3,6),(4,6),(5,6),(6,6),(7,6),(8,6),(9,6),(10,6),
(1,7),(2,7),(3,7),(4,7),(5,7),(6,7),(7,7),(8,7),(9,7),
(1,8),(2,8),(3,8),(4,8),(5,8),(6,8),(7,8),(8,8),
(1,9),(2,9),(3,9),(4,9),(5,9),(6,9),(7,9),
(1,10),(2,10),(3,10),(4,10),(5,10),(6,10),
(1,11),(2,11),(3,11),(4,11),(5,11),
(1,12),(2,12),(3,12),(4,12),
(1,13),(2,13),(3,13),
(1,14),(2,14),
(1,15)
);
impl<const SRC:usize,const F:usize> Fixed<SRC,F>{
pub fn resize_into<const DST:usize>(self)->Fixed<DST,F>{
@@ -318,7 +369,7 @@ impl<const SRC:usize,const F:usize> Fixed<SRC,F>{
}
}
macro_rules! impl_const{
macro_rules! impl_not_const_generic{
($n:expr)=>{
impl Fixed<{$n*2},{$n*2*32}>{
pub fn halve_precision(self)->Fixed<$n,{$n*32}>{
@@ -367,11 +418,11 @@ macro_rules! impl_const{
}
}
}
impl_const!(1);
impl_const!(2);
impl_const!(3);
impl_const!(4);
impl_const!(5);
impl_const!(6);
impl_const!(7);
impl_const!(8);
impl_not_const_generic!(1);
impl_not_const_generic!(2);
impl_not_const_generic!(3);
impl_not_const_generic!(4);
impl_not_const_generic!(5);
impl_not_const_generic!(6);
impl_not_const_generic!(7);
impl_not_const_generic!(8);

View File

@@ -20,6 +20,20 @@ fn test_wide_mul(){
assert_eq!(aa,crate::types::I64F64::ONE);
}
#[test]
fn test_wide_div(){
let a=I32F32::ONE*4;
let b=I32F32::ONE*2;
let wide_a=a.wide_mul_1_1(I32F32::ONE);
let wide_b=b.wide_mul_1_1(I32F32::ONE);
let ab=a.wide_div_1_1(b);
assert_eq!(ab,crate::types::I64F64::ONE*2);
let wab=wide_a.wide_div_2_1(b);
assert_eq!(wab,crate::fixed::Fixed::<3,96>::ONE*2);
let awb=a.wide_div_1_2(wide_b);
assert_eq!(awb,crate::fixed::Fixed::<3,96>::ONE*2);
}
#[test]
fn test_wide_mul_repeated() {
let a=I32F32::from(2);
@@ -51,7 +65,7 @@ fn test_sqrt_zero(){
#[test]
fn test_sqrt_low(){
let a=I32F32::HALF;
let b=a*a;
let b=a.fixed_mul(a);
assert_eq!(b.sqrt(),a);
}
fn find_equiv_sqrt_via_f64(n:I32F32)->I32F32{

View File

@@ -4,9 +4,10 @@ version = "0.1.0"
edition = "2021"
[features]
default=["fixed_wide"]
fixed_wide=["dep:fixed_wide"]
default=["fixed_wide","named-fields"]
named-fields=[]
fixed_wide=["dep:fixed_wide","dep:paste"]
[dependencies]
fixed_wide = { version = "0.1.0", path = "../fixed_wide", optional = true }
paste = "1.0.15"
paste = { version = "1.0.15", optional = true }

View File

@@ -1,14 +1,10 @@
mod macros;
mod vector;
mod matrix;
pub mod types;
pub mod vector;
pub mod matrix;
pub use vector::Vector2;
pub use vector::Vector3;
pub use vector::Vector4;
pub use matrix::Matrix2;
pub use matrix::Matrix3;
pub use matrix::Matrix4;
#[cfg(feature="named-fields")]
mod named;
#[cfg(test)]
mod tests;

View File

@@ -1,138 +1 @@
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_common {
( $struct: ident { $($field: ident), + }, $size: expr ) => {
impl<T> $struct<T> {
/// Constructs a new vector with the specified values for each field.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let vec2 = Vector2::new(0, 0);
///
/// assert_eq!(vec2.x, 0);
/// assert_eq!(vec2.y, 0);
/// ```
#[inline(always)]
pub const fn new( $($field: T), + ) -> Self {
Self {
$( $field ), +
}
}
/// Consumes the vector and returns its values as an array.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let vec2 = Vector2::new(0, 0);
/// let array = vec2.to_array();
///
/// assert_eq!(array, [0, 0]);
/// ```
#[inline(always)]
pub fn to_array(self) -> [T; $size] {
[ $(self.$field), + ]
}
/// Consumes the vector and returns a new vector with the given function applied on each field.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let vec2 = Vector2::new(1, 2)
/// .map(|i| i * 2);
///
/// assert_eq!(vec2, Vector2::new(2, 4));
/// ```
#[inline]
pub fn map<F, U>(self, f: F) -> $struct<U>
where
F: Fn(T) -> U
{
$struct {
$( $field: f(self.$field) ), +
}
}
}
impl<T: Copy> $struct<T> {
/// Constructs a vector using the given `value` as the value for all of its fields.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let vec2 = Vector2::from_value(0);
///
/// assert_eq!(vec2, Vector2::new(0, 0));
/// ```
#[inline(always)]
pub const fn from_value(value: T) -> Self {
Self {
$( $field: value ), +
}
}
}
impl<T> From<[T; $size]> for $struct<T> {
fn from(from: [T; $size]) -> Self {
let mut iterator = from.into_iter();
Self {
// SAFETY: We know the size of `from` so `iterator.next()` is always `Some(..)`
$( $field: unsafe { iterator.next().unwrap_unchecked() } ), +
}
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for $struct<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let identifier = core::stringify!($struct);
f.debug_struct(identifier)
$( .field( core::stringify!($field), &self.$field ) ) +
.finish()
}
}
impl<T: PartialEq> PartialEq for $struct<T> {
fn eq(&self, other: &Self) -> bool {
$( self.$field == other.$field ) && +
}
}
impl<T: Eq> Eq for $struct<T> { }
impl<T: core::hash::Hash> core::hash::Hash for $struct<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
$( self.$field.hash(state); ) +
}
}
impl<T: Clone> Clone for $struct<T> {
fn clone(&self) -> Self {
Self {
$( $field: self.$field.clone() ), +
}
}
}
impl<T: Copy> Copy for $struct<T> { }
impl<T: Default> Default for $struct<T> {
fn default() -> Self {
Self {
$( $field: T::default() ), +
}
}
}
}
}

View File

@@ -2,22 +2,18 @@
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_operations_2arg_not_const_generic {
(
($struct: ident { $($field: ident), + }, $size: expr),
(),
($lhs:expr, $rhs:expr)
) => {
impl $struct<fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
paste::item!{
#[inline]
pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:$struct<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->$struct<fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
$struct{
$( $field: self.$field.[<wide_mul_ $lhs _ $rhs>](rhs.$field) ), +
}
pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:Vector<N,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Vector<N,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
self.map_zip(rhs,|(a,b)|a.[<wide_mul_ $lhs _ $rhs>](b))
}
#[inline]
pub fn [<wide_dot_ $lhs _ $rhs>](self,rhs:$struct<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
$crate::sum_repeating!(
$( + (self.$field.[<wide_mul_ $lhs _ $rhs>](rhs.$field)) ) +
)
pub fn [<wide_dot_ $lhs _ $rhs>](self,rhs:Vector<N,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
self.array.into_iter().zip(rhs.array).map(|(a,b)|a.[<wide_mul_ $lhs _ $rhs>](b)).sum()
}
}
}
@@ -27,16 +23,14 @@ macro_rules! impl_wide_vector_operations_2arg_not_const_generic {
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_operations_1arg_not_const_generic {
(
($struct: ident { $($field: ident), + }, $size: expr),
(),
$n:expr
) => {
impl $struct<fixed_wide::fixed::Fixed<{$n},{$n*32}>>{
impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<{$n},{$n*32}>>{
paste::item!{
#[inline]
pub fn wide_length_squared(&self)->fixed_wide::fixed::Fixed<{$n*2},{$n*2*32}>{
$crate::sum_repeating!(
$( + self.$field.[<wide_mul_ $n _ $n>](self.$field) ) +
)
self.array.into_iter().map(|t|t.[<wide_mul_ $n _ $n>](t)).sum()
}
}
}
@@ -77,40 +71,28 @@ macro_rules! do_macro_8{
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_operations {
( $struct: ident { $($field: ident), + }, $size: expr ) => {
$crate::do_macro_8!(impl_wide_vector_operations_1arg_not_const_generic,($struct { $($field), + }, $size));
$crate::do_macro_8x8!(impl_wide_vector_operations_2arg_not_const_generic,($struct { $($field), + }, $size));
() => {
$crate::do_macro_8!(impl_wide_vector_operations_1arg_not_const_generic,());
$crate::do_macro_8x8!(impl_wide_vector_operations_2arg_not_const_generic,());
};
}
// Notes:
// Mat3<Vec2>.dot(Vec2) -> Vec3
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
// mat.mat can be implemented off the back of mat.vec
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul {
macro_rules! impl_vector_3_wide_cross {
(
//TODO: Fixed point impls
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr),
($rhs_struct_inner: ident { $($rhs_field_inner: ident), + }, $rhs_matrix_inner: ident { $($rhs_matrix_field_inner: ident), + }, $rhs_size_inner: expr),
($lhs: expr, $rhs: expr)
) => {
impl $struct_outer<$struct_inner<fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>>{
(),
($lhs:expr, $rhs:expr)
)=>{
impl Vector<3,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
paste::item!{
#[inline]
pub fn [<wide_dot_ $size_outer x $size_inner _ $size_inner x $rhs_size_inner _ $lhs _ $rhs>](self,rhs:$matrix_inner<$rhs_struct_inner<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>>)->$struct_outer<$rhs_struct_inner<fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>>{
//just made this up, don't trust it
let tr=rhs.transpose();
//TODO: use a macro expansion instead of transpose and map
self.map(|axis|
tr.map(|trax|
axis.[<wide_dot_ $lhs _ $rhs>](trax)
).to_vector()
)
pub fn [<wide_cross_ $lhs _ $rhs>](self,rhs:Vector<3,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Vector<3,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
Vector::new([
self.y.[<wide_mul_ $lhs _ $rhs>](rhs.z)-self.z.[<wide_mul_ $lhs _ $rhs>](rhs.y),
self.z.[<wide_mul_ $lhs _ $rhs>](rhs.x)-self.x.[<wide_mul_ $lhs _ $rhs>](rhs.z),
self.x.[<wide_mul_ $lhs _ $rhs>](rhs.y)-self.y.[<wide_mul_ $lhs _ $rhs>](rhs.x),
])
}
}
}
@@ -119,80 +101,112 @@ macro_rules! impl_matrix_wide_mul {
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_shim {
macro_rules! impl_vector_wide_3 {
()=>{
$crate::do_macro_8x8!(impl_vector_3_wide_cross,());
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! do_macro_4_dumb{
(
($outer_info:tt,$inner_info:tt,$rhs_info:tt),
$macro:ident,
$any:tt
)=>{
$crate::macro_repeated!($macro, $any, (1,2),(2,4),(3,6),(4,8));
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_dot {
(
(),
($lhs: expr, $rhs: expr)
) => {
$crate::impl_matrix_wide_mul!($outer_info,$inner_info,$rhs_info,($lhs,$rhs));
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_8x8 {
(
($outer_info:tt,$inner_info:tt),
$rhs_info:tt
) => {
$crate::do_macro_8x8!(impl_matrix_wide_mul_shim,($outer_info,$inner_info,$rhs_info));
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_repeat_rhs {
(
($outer_info:tt,($($rhs_info:tt),+)),
$inner_info:tt
) => {
$crate::macro_repeated!(impl_matrix_wide_mul_8x8,($outer_info,$inner_info),$($rhs_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_matrix_operations_2arg_not_const_generic {
(
$lhs: expr, $rhs: expr,
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr)
) => {
/* TODO: nasty determinant macro
impl<U:std::ops::Add<Output=U>,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
impl<const X:usize,const Y:usize> Matrix<X,Y,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
paste::item!{
#[inline]
pub fn wide_dot(&self) -> U {
$crate::sum_repeating!(
$( + self.$field.wide_mul(self.$field) ) +
)
pub fn [<wide_dot_ $lhs _ $rhs>]<const Z:usize>(self,rhs:Matrix<Z,X,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Matrix<Z,Y,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
let mut array_of_iterators=rhs.array.map(|axis|axis.into_iter().cycle());
Matrix::new(
self.array.map(|axis|
core::array::from_fn(|_|
// axis dot product with transposed rhs array
axis.iter().zip(
array_of_iterators.iter_mut()
).map(|(&lhs_value,rhs_iter)|
lhs_value.[<wide_mul_ $lhs _ $rhs>](rhs_iter.next().unwrap())
).sum()
)
)
)
}
}
}
*/
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_matrix_operations_1arg_not_const_generic {
(
$n: expr,
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
) => {
/* TODO: nasty determinant macro
impl<U:std::ops::Add<Output=U>,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
#[inline]
pub fn wide_det(&self) -> U {
$crate::sum_repeating!(
$( + self.$field.wide_mul(self.$field) ) +
)
}
}
*/
};
}
}
// HACK: Allows us to sum repeating tokens in macros.
// See: https://stackoverflow.com/a/60187870/17452730
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! sum_repeating {
( + $($item: tt) * ) => {
$($item) *
};
macro_rules! impl_matrix_wide_dot_8x8 {
() => {
$crate::do_macro_8x8!(impl_matrix_wide_dot,());
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_3x3_det_not_const_generic {
(
$n: expr,
$_2n: expr
)=>{
impl Matrix<3,3,fixed_wide::fixed::Fixed<$n,{$n*32}>>{
paste::item!{
pub fn [<wide_det_3x3_ $n>](self)->fixed_wide::fixed::Fixed<{$n*3},{$n*3*32}>{
//[<wide_dot_ $n _ $n*2>] will not compile, so the doubles are hardcoded above
self.x_axis.[<wide_dot_ $n _ $_2n>](self.y_axis.[<wide_cross_ $n _ $n>](self.z_axis))
}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_3x3_det_not_const_generic_shim {
(
(),($n: expr,$_2n: expr)
)=>{
$crate::impl_matrix_wide_3x3_det_not_const_generic!($n,$_2n);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_3x3_adjugate_not_const_generic {
(
(),
$n: expr
)=>{
impl Matrix<3,3,fixed_wide::fixed::Fixed<$n,{$n*32}>>{
paste::item!{
pub fn [<wide_adjugate_3x3_ $n>](self)->Matrix<3,3,fixed_wide::fixed::Fixed<{$n*2},{$n*2*32}>>{
Matrix::new([
[self.y_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.z)-self.y_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.y),self.x_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.y)-self.x_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.z),self.x_axis.y.[<wide_mul_ $n _ $n>](self.y_axis.z)-self.x_axis.z.[<wide_mul_ $n _ $n>](self.y_axis.y)],
[self.y_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.x)-self.y_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.z),self.x_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.z)-self.x_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.x),self.x_axis.z.[<wide_mul_ $n _ $n>](self.y_axis.x)-self.x_axis.x.[<wide_mul_ $n _ $n>](self.y_axis.z)],
[self.y_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.y)-self.y_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.x),self.x_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.x)-self.x_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.y),self.x_axis.x.[<wide_mul_ $n _ $n>](self.y_axis.y)-self.x_axis.y.[<wide_mul_ $n _ $n>](self.y_axis.x)],
])
}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_3x3 {
()=>{
$crate::do_macro_4_dumb!(impl_matrix_wide_3x3_det_not_const_generic_shim,());
$crate::do_macro_8!(impl_matrix_wide_3x3_adjugate_not_const_generic,());
}
}

View File

@@ -1,192 +1,155 @@
// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license)
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix {
(
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr)
) => {
$crate::impl_common!($struct_outer { $($field_outer), + }, $size_outer);
impl<U> $struct_outer<U> {
() => {
impl<const X:usize,const Y:usize,T> Matrix<X,Y,T>{
#[inline(always)]
pub fn to_vector(self) -> $vector_outer<U> {
$vector_outer {
$(
$vector_field_outer: self.$field_outer
), +
}
pub const fn new(array:[[T;X];Y])->Self{
Self{array}
}
#[inline(always)]
pub fn to_array(self)->[[T;X];Y]{
self.array
}
#[inline]
pub fn map<F,U>(self,f:F)->Matrix<X,Y,U>
where
F:Fn(T)->U
{
Matrix::new(
self.array.map(|inner|inner.map(&f)),
)
}
#[inline]
pub fn transpose(self)->Matrix<Y,X,T>{
//how did I think of this
let mut array_of_iterators=self.array.map(|axis|axis.into_iter());
Matrix::new(
core::array::from_fn(|_|
array_of_iterators.each_mut().map(|iter|
iter.next().unwrap()
)
)
)
}
#[inline]
// MatY<VecX>.MatX<VecZ> = MatY<VecZ>
pub fn dot<const Z:usize,U,V>(self,rhs:Matrix<Z,X,U>)->Matrix<Z,Y,V>
where
T:core::ops::Mul<U,Output=V>+Copy,
V:core::iter::Sum,
U:Copy,
{
let mut array_of_iterators=rhs.array.map(|axis|axis.into_iter().cycle());
Matrix::new(
self.array.map(|axis|
core::array::from_fn(|_|
// axis dot product with transposed rhs array
axis.iter().zip(
array_of_iterators.iter_mut()
).map(|(&lhs_value,rhs_iter)|
lhs_value*rhs_iter.next().unwrap()
).sum()
)
)
)
}
}
impl<const X:usize,const Y:usize,T> Matrix<X,Y,T>
where
T:Copy
{
pub const fn from_value(value:T)->Self{
Self::new([[value;X];Y])
}
}
impl<const X:usize,const Y:usize,T:Default> Default for Matrix<X,Y,T>{
fn default()->Self{
Self::new(
core::array::from_fn(|_|core::array::from_fn(|_|Default::default()))
)
}
}
#[cfg(feature="fixed_wide")]
$crate::impl_matrix_wide_dot_8x8!();
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_extend {
( $x: expr, $y: expr ) => {
impl<T> Matrix<$x,$y,T>{
#[inline]
pub fn extend_row(self,value:Vector<$x,T>)->Matrix<$x,{$y+1},T>{
let mut iter=self.array.into_iter().chain(core::iter::once(value.array));
Matrix::new(
core::array::from_fn(|_|iter.next().unwrap()),
)
}
#[inline]
pub fn extend_column(self,value:Vector<$y,T>)->Matrix<{$x+1},$y,T>{
let mut iter_rows=value.array.into_iter();
Matrix::new(
self.array.map(|axis|{
let mut elements_iter=axis.into_iter().chain(core::iter::once(iter_rows.next().unwrap()));
core::array::from_fn(|_|elements_iter.next().unwrap())
})
)
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_shim {
macro_rules! impl_matrix_named_fields_shape {
(
(),
$matrix_info:tt
($struct_outer:ident, $size_outer: expr),
($size_inner: expr)
) => {
$crate::impl_matrix!($matrix_info);
impl<T> core::ops::Deref for Matrix<$size_outer,$size_inner,T>{
type Target=$struct_outer<Vector<$size_inner,T>>;
fn deref(&self)->&Self::Target{
unsafe{core::mem::transmute(&self.array)}
}
}
impl<T> core::ops::DerefMut for Matrix<$size_outer,$size_inner,T>{
fn deref_mut(&mut self)->&mut Self::Target{
unsafe{core::mem::transmute(&mut self.array)}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrices {
(
($($matrix_info:tt),+),
$vector_infos:tt
) => {
$crate::macro_repeated!(impl_matrix_shim,(),$($matrix_info),+);
$crate::macro_repeated!(impl_matrix_inner_shim,$vector_infos,$($matrix_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_inner_shim {
macro_rules! impl_matrix_named_fields_shape_shim {
(
($($vector_info:tt),+),
$matrix_info:tt
) => {
$crate::macro_repeated!(impl_matrix_inner,$matrix_info,$($vector_info),+);
$crate::macro_repeated!(impl_matrix_named_fields_shape,$matrix_info,$($vector_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_named_fields {
(
($($matrix_info:tt),+),
$vector_infos:tt
) => {
$crate::macro_repeated!(impl_matrix_named_fields_shape_shim,$vector_infos,$($matrix_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_3x3 {
()=>{
#[cfg(feature="fixed_wide")]
$crate::macro_repeated!(impl_matrix_wide_mul_repeat_rhs,($matrix_info,($($vector_info),+)),$($vector_info),+);
$crate::impl_matrix_wide_3x3!();
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_inner {
(
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr)
) => {
impl<T> $struct_outer<$struct_inner<T>> {
#[inline(always)]
pub fn to_array_2d(self) -> [[T; $size_inner]; $size_outer] {
[ $(self.$field_outer.to_array()), + ]
}
#[inline]
pub fn map_2d<F, U>(self, f: F) -> $struct_outer<$struct_inner<U>>
where
F: Fn(T) -> U
{
$crate::matrix_map2d_outer!{f,self,($struct_outer { $($field_outer), + }),($struct_inner { $($field_inner), + })}
}
#[inline]
pub fn transpose(self) -> $matrix_inner<$vector_outer<T>>{
$crate::matrix_transpose_outer!{self,
($matrix_inner { $($matrix_field_inner), + }),($struct_inner { $($field_inner), + }),
($vector_outer { $($vector_field_outer), + }),($struct_outer { $($field_outer), + })
}
}
}
impl<T: Copy> $struct_outer<$struct_inner<T>> {
#[inline(always)]
pub const fn from_value_2d(value: T) -> Self {
Self {
$( $field_outer: $struct_inner::from_value(value) ), +
}
}
//TODO: diagonal
}
// Impl floating-point based methods
//#[cfg(feature="fixed_wide_traits")]
//$crate::impl_wide_matrix_operations!( ($struct_outer { $($field_outer), + }, $size_outer), ($struct_inner, $size_inner), $fields_inner );
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! matrix_map2d_outer {
( $f:ident, $value:ident, ($struct_outer: ident { $($field_outer: ident), + }), $unparsed_inner:tt ) => {
$struct_outer {
$(
$field_outer: $crate::matrix_map2d_inner!{$f,$value,$field_outer,$unparsed_inner}
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! matrix_map2d_inner {
( $f:ident, $value:ident, $field_outer:ident, ($struct_inner: ident { $($field_inner: ident), + }) ) => {
$struct_inner {
$(
$field_inner: $f($value.$field_outer.$field_inner)
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! matrix_transpose_outer {
(
$value:ident,
($struct_outer: ident { $($field_outer: ident), + }),
($old_outer: ident { $($old_field_outer: ident), + }),
$fields_inner:tt,
$old_fields_inner:tt
) => {
$struct_outer {
$(
$field_outer: $crate::matrix_transpose_inner!{$value,$old_field_outer,$fields_inner,$old_fields_inner}
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! matrix_transpose_inner {
( $value:ident, $field_outer:ident,
($struct_inner: ident { $($field_inner: ident), + }),
($old_struct_inner: ident { $($old_field_inner: ident), + })
) => {
$struct_inner {
$(
$field_inner: $value.$old_field_inner.$field_outer
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_operator {
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident, $output: ty ) => {
impl<T:core::ops::$trait<Output=T>> core::ops::$trait for $struct<T> {
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
Self {
$( $field: self.$field.$method(other.$field) ), +
}
}
}
impl<T:core::ops::$trait<Output=T>+Copy> core::ops::$trait<T> for $struct<T>{
type Output = $output;
fn $method(self, other: T) -> Self::Output {
$struct {
$( $field: self.$field.$method(other) ), +
}
}
}
};
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident ) => {
impl<T: core::ops::$trait> core::ops::$trait for $struct<T> {
fn $method(&mut self, other: Self) {
$( self.$field.$method(other.$field) ); +
}
}
impl<T: core::ops::$trait + Copy> core::ops::$trait<T> for $struct<T> {
fn $method(&mut self, other: T) {
$( self.$field.$method(other) ); +
}
}
};
}

View File

@@ -1,146 +1,203 @@
// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license)
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector {
( $struct: ident { $($field: ident), + }, $size: expr ) => {
$crate::impl_common!($struct { $($field), + }, $size);
impl<T: Ord> $struct<T> {
pub fn min(self, rhs: Self) -> $struct<T> {
$struct{
$( $field: self.$field.min(rhs.$field) ), +
}
() => {
impl<const N:usize,T> Vector<N,T>{
#[inline(always)]
pub const fn new(array:[T;N])->Self{
Self{array}
}
pub fn max(self, rhs: Self) -> $struct<T> {
$struct{
$( $field: self.$field.max(rhs.$field) ), +
}
#[inline(always)]
pub fn to_array(self)->[T;N]{
self.array
}
pub fn cmp(self, rhs: Self) -> $struct<core::cmp::Ordering> {
$struct{
$( $field: self.$field.cmp(&rhs.$field) ), +
}
#[inline]
pub fn map<F,U>(self,f:F)->Vector<N,U>
where
F:Fn(T)->U
{
Vector::new(
self.array.map(f)
)
}
pub fn lt(self, rhs: Self) -> $struct<bool> {
$struct{
$( $field: self.$field.lt(&rhs.$field) ), +
}
#[inline]
pub fn map_zip<F,U,V>(self,other:Vector<N,U>,f:F)->Vector<N,V>
where
F:Fn((T,U))->V,
{
let mut iter=self.array.into_iter().zip(other.array);
Vector::new(
core::array::from_fn(|_|f(iter.next().unwrap())),
)
}
pub fn gt(self, rhs: Self) -> $struct<bool> {
$struct{
$( $field: self.$field.gt(&rhs.$field) ), +
}
}
pub fn ge(self, rhs: Self) -> $struct<bool> {
$struct{
$( $field: self.$field.ge(&rhs.$field) ), +
}
}
pub fn le(self, rhs: Self) -> $struct<bool> {
$struct{
$( $field: self.$field.le(&rhs.$field) ), +
}
}
impl<const N:usize,T:Copy> Vector<N,T>{
#[inline(always)]
pub const fn from_value(value:T)->Self{
Self::new([value;N])
}
}
impl $struct<bool>{
impl<const N:usize,T:Default> Default for Vector<N,T>{
fn default()->Self{
Self::new(
core::array::from_fn(|_|Default::default())
)
}
}
impl<const N:usize,T:Ord> Vector<N,T>{
#[inline]
pub fn min(self,rhs:Self)->Self{
self.map_zip(rhs,|(a,b)|a.min(b))
}
#[inline]
pub fn max(self,rhs:Self)->Self{
self.map_zip(rhs,|(a,b)|a.max(b))
}
#[inline]
pub fn cmp(self,rhs:Self)->Vector<N,core::cmp::Ordering>{
self.map_zip(rhs,|(a,b)|a.cmp(&b))
}
#[inline]
pub fn lt(self,rhs:Self)->Vector<N,bool>{
self.map_zip(rhs,|(a,b)|a.lt(&b))
}
#[inline]
pub fn gt(self,rhs:Self)->Vector<N,bool>{
self.map_zip(rhs,|(a,b)|a.gt(&b))
}
#[inline]
pub fn ge(self,rhs:Self)->Vector<N,bool>{
self.map_zip(rhs,|(a,b)|a.ge(&b))
}
#[inline]
pub fn le(self,rhs:Self)->Vector<N,bool>{
self.map_zip(rhs,|(a,b)|a.le(&b))
}
}
impl<const N:usize> Vector<N,bool>{
#[inline]
pub fn all(&self)->bool{
const ALL:[bool;$size]=[true;$size];
core::matches!(self.to_array(),ALL)
self.array==[true;N]
}
#[inline]
pub fn any(&self)->bool{
$( self.$field )|| +
self.array!=[false;N]
}
}
impl<T: core::ops::Neg<Output = T>> core::ops::Neg for $struct<T> {
type Output = Self;
fn neg(self) -> Self::Output {
Self {
$( $field: -self.$field ), +
}
impl<const N:usize,T:core::ops::Neg<Output=V>,V> core::ops::Neg for Vector<N,T>{
type Output=Vector<N,V>;
fn neg(self)->Self::Output{
Vector::new(
self.array.map(|t|-t)
)
}
}
// Impl arithmetic pperators
$crate::impl_vector_operator!( $struct { $($field), + }, AddAssign, add_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Add, add, Self );
$crate::impl_vector_operator!( $struct { $($field), + }, SubAssign, sub_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Sub, sub, Self );
$crate::impl_vector_operator!( $struct { $($field), + }, MulAssign, mul_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Mul, mul, Self );
$crate::impl_vector_operator!( $struct { $($field), + }, DivAssign, div_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Div, div, Self );
$crate::impl_vector_operator!( $struct { $($field), + }, RemAssign, rem_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Rem, rem, Self );
// Impl arithmetic operators
$crate::impl_vector_assign_operator!(AddAssign, add_assign );
$crate::impl_vector_operator!(Add, add );
$crate::impl_vector_assign_operator!(SubAssign, sub_assign );
$crate::impl_vector_operator!(Sub, sub );
$crate::impl_vector_assign_operator!(MulAssign, mul_assign );
$crate::impl_vector_operator!(Mul, mul );
$crate::impl_vector_assign_operator!(DivAssign, div_assign );
$crate::impl_vector_operator!(Div, div );
$crate::impl_vector_assign_operator!(RemAssign, rem_assign );
$crate::impl_vector_operator!(Rem, rem );
// Impl bitwise operators
$crate::impl_vector_operator!( $struct { $($field), + }, BitAndAssign, bitand_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, BitAnd, bitand, Self );
$crate::impl_vector_operator!( $struct { $($field), + }, BitOrAssign, bitor_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, BitOr, bitor, Self );
$crate::impl_vector_operator!( $struct { $($field), + }, BitXorAssign, bitxor_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, BitXor, bitxor, Self );
$crate::impl_vector_assign_operator!(BitAndAssign, bitand_assign );
$crate::impl_vector_operator!(BitAnd, bitand );
$crate::impl_vector_assign_operator!(BitOrAssign, bitor_assign );
$crate::impl_vector_operator!(BitOr, bitor );
$crate::impl_vector_assign_operator!(BitXorAssign, bitxor_assign );
$crate::impl_vector_operator!(BitXor, bitxor );
// Impl floating-point based methods
#[cfg(feature="fixed_wide")]
$crate::impl_wide_vector_operations!( $struct { $($field), + }, $size );
};
$crate::impl_wide_vector_operations!();
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_extend {
( $struct: ident { $($field: ident), + }, $struct_extended: ident, $field_extended: ident ) => {
impl<T> $struct<T> {
#[inline(always)]
pub fn extend(self,value:T) -> $struct_extended<T> {
$struct_extended {
$( $field:self.$field, ) +
$field_extended:value
}
}
}
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_operator {
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident, $output: ty ) => {
impl<T:core::ops::$trait<Output=T>> core::ops::$trait for $struct<T> {
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
Self {
$( $field: self.$field.$method(other.$field) ), +
}
($trait: ident, $method: ident ) => {
impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
type Output=Vector<N,V>;
fn $method(self,rhs:Vector<N,U>)->Self::Output{
self.map_zip(rhs,|(a,b)|a.$method(b))
}
}
impl<T:core::ops::$trait<Output=T>+Copy> core::ops::$trait<T> for $struct<T>{
type Output = $output;
fn $method(self, other: T) -> Self::Output {
$struct {
$( $field: self.$field.$method(other) ), +
}
impl<const N:usize,T:core::ops::$trait<i64,Output=T>> core::ops::$trait<i64> for Vector<N,T>{
type Output=Self;
fn $method(self,rhs:i64)->Self::Output{
self.map(|t|t.$method(rhs))
}
}
};
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident ) => {
impl<T: core::ops::$trait> core::ops::$trait for $struct<T> {
fn $method(&mut self, other: Self) {
$( self.$field.$method(other.$field) ); +
}
}
impl<T: core::ops::$trait + Copy> core::ops::$trait<T> for $struct<T> {
fn $method(&mut self, other: T) {
$( self.$field.$method(other) ); +
}
}
};
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_assign_operator {
($trait: ident, $method: ident ) => {
impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
fn $method(&mut self,rhs:Vector<N,U>){
self.array.iter_mut().zip(rhs.array)
.for_each(|(a,b)|a.$method(b))
}
}
impl<const N:usize,T:core::ops::$trait<i64>> core::ops::$trait<i64> for Vector<N,T>{
fn $method(&mut self,rhs:i64){
self.array.iter_mut()
.for_each(|t|t.$method(rhs))
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_extend {
( $size: expr ) => {
impl<T> Vector<$size,T>{
#[inline]
pub fn extend(self,value:T)->Vector<{$size+1},T>{
let mut iter=self.array.into_iter().chain(core::iter::once(value));
Vector::new(
core::array::from_fn(|_|iter.next().unwrap()),
)
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_named_fields {
( $struct:ident, $size: expr ) => {
impl<T> core::ops::Deref for Vector<$size,T>{
type Target=$struct<T>;
fn deref(&self)->&Self::Target{
unsafe{core::mem::transmute(&self.array)}
}
}
impl<T> core::ops::DerefMut for Vector<$size,T>{
fn deref_mut(&mut self)->&mut Self::Target{
unsafe{core::mem::transmute(&mut self.array)}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_3 {
()=>{
#[cfg(feature="fixed_wide")]
$crate::impl_vector_wide_3!();
}
}

View File

@@ -1,36 +1,16 @@
use crate::{Vector2,Vector3,Vector4};
use crate::vector::Vector;
pub struct Matrix2<T> {
pub x_axis: T,
pub y_axis: T,
}
pub struct Matrix3<T> {
pub x_axis: T,
pub y_axis: T,
pub z_axis: T,
}
pub struct Matrix4<T> {
pub x_axis: T,
pub y_axis: T,
pub z_axis: T,
pub w_axis: T,
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
pub struct Matrix<const X:usize,const Y:usize,T>{
pub(crate) array:[[T;X];Y],
}
crate::impl_extend!(Matrix2 { x_axis, y_axis }, Matrix3, z_axis);
crate::impl_extend!(Matrix3 { x_axis, y_axis, z_axis }, Matrix4, w_axis);
//TODO: extend vertically
crate::impl_matrix!();
crate::impl_matrices!(
//outer struct and equivalent vector
(
(Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2),
(Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3),
(Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4)
),
//inner struct and equivalent matrix
(
(Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2),
(Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3),
(Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4)
)
);
crate::impl_matrix_extend!(2,2);
crate::impl_matrix_extend!(2,3);
crate::impl_matrix_extend!(3,2);
crate::impl_matrix_extend!(3,3);
//Special case 3x3 matrix operations because I cba to write macros for the arbitrary cases
crate::impl_matrix_3x3!();

View File

@@ -0,0 +1,59 @@
use crate::vector::Vector;
use crate::matrix::Matrix;
#[repr(C)]
pub struct Vector2<T> {
pub x: T,
pub y: T,
}
#[repr(C)]
pub struct Vector3<T> {
pub x: T,
pub y: T,
pub z: T,
}
#[repr(C)]
pub struct Vector4<T> {
pub x: T,
pub y: T,
pub z: T,
pub w: T,
}
crate::impl_vector_named_fields!(Vector2, 2);
crate::impl_vector_named_fields!(Vector3, 3);
crate::impl_vector_named_fields!(Vector4, 4);
#[repr(C)]
pub struct Matrix2<T> {
pub x_axis: T,
pub y_axis: T,
}
#[repr(C)]
pub struct Matrix3<T> {
pub x_axis: T,
pub y_axis: T,
pub z_axis: T,
}
#[repr(C)]
pub struct Matrix4<T> {
pub x_axis: T,
pub y_axis: T,
pub z_axis: T,
pub w_axis: T,
}
crate::impl_matrix_named_fields!(
//outer struct
(
(Matrix2, 2),
(Matrix3, 3),
(Matrix4, 4)
),
//inner struct
(
(2),
(3),
(4)
)
);

View File

@@ -1,4 +1,4 @@
use crate::{Vector2,Vector3,Vector4,Matrix3,Matrix4};
use crate::types::{Matrix3,Matrix2x3,Matrix4x3,Matrix2x4,Vector3};
type Planar64=fixed_wide::types::I32F32;
type Planar64Wide1=fixed_wide::types::I64F64;
@@ -12,7 +12,7 @@ fn wide_vec3(){
let v2=v1.wide_mul_2_2(v1);
let v3=v2.wide_mul_4_4(v2);
assert_eq!(v3,Vector3::from_value(Planar64Wide3::from(3i128.pow(8))));
assert_eq!(v3.array,Vector3::from_value(Planar64Wide3::from(3i128.pow(8))).array);
}
#[test]
@@ -37,27 +37,58 @@ fn wide_vec3_length_squared(){
#[test]
fn wide_matrix_dot(){
let lhs=Matrix3::from([
Vector4::from([Planar64::from(1),Planar64::from(2),Planar64::from(3),Planar64::from(4)]),
Vector4::from([Planar64::from(5),Planar64::from(6),Planar64::from(7),Planar64::from(8)]),
Vector4::from([Planar64::from(9),Planar64::from(10),Planar64::from(11),Planar64::from(12)]),
let lhs=Matrix4x3::new([
[Planar64::from(1),Planar64::from(2),Planar64::from(3),Planar64::from(4)],
[Planar64::from(5),Planar64::from(6),Planar64::from(7),Planar64::from(8)],
[Planar64::from(9),Planar64::from(10),Planar64::from(11),Planar64::from(12)],
]);
let rhs=Matrix4::from([
Vector2::from([Planar64::from(1),Planar64::from(2)]),
Vector2::from([Planar64::from(3),Planar64::from(4)]),
Vector2::from([Planar64::from(5),Planar64::from(6)]),
Vector2::from([Planar64::from(7),Planar64::from(8)]),
let rhs=Matrix2x4::new([
[Planar64::from(1),Planar64::from(2)],
[Planar64::from(3),Planar64::from(4)],
[Planar64::from(5),Planar64::from(6)],
[Planar64::from(7),Planar64::from(8)],
]);
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
let m_dot=lhs.wide_dot_3x4_4x2_1_1(rhs);
let m_dot=lhs.wide_dot_1_1(rhs);
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
//Out[1]= {{50, 60}, {114, 140}, {178, 220}}
assert_eq!(
m_dot,
Matrix3::from([
Vector2::from([Planar64Wide1::from(50),Planar64Wide1::from(60)]),
Vector2::from([Planar64Wide1::from(114),Planar64Wide1::from(140)]),
Vector2::from([Planar64Wide1::from(178),Planar64Wide1::from(220)]),
])
m_dot.array,
Matrix2x3::new([
[Planar64Wide1::from(50),Planar64Wide1::from(60)],
[Planar64Wide1::from(114),Planar64Wide1::from(140)],
[Planar64Wide1::from(178),Planar64Wide1::from(220)],
]).array
);
}
#[test]
fn wide_matrix_det(){
let m=Matrix3::new([
[Planar64::from(1),Planar64::from(2),Planar64::from(3)],
[Planar64::from(4),Planar64::from(5),Planar64::from(7)],
[Planar64::from(6),Planar64::from(8),Planar64::from(9)],
]);
// In[2]:= Det[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}]
// Out[2]= 7
assert_eq!(m.wide_det_3x3_1(),fixed_wide::fixed::Fixed::<3,96>::from(7));
}
#[test]
fn wide_matrix_adjugate(){
let m=Matrix3::new([
[Planar64::from(1),Planar64::from(2),Planar64::from(3)],
[Planar64::from(4),Planar64::from(5),Planar64::from(7)],
[Planar64::from(6),Planar64::from(8),Planar64::from(9)],
]);
// In[6]:= Adjugate[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}]
// Out[6]= {{-11, 6, -1}, {6, -9, 5}, {2, 4, -3}}
assert_eq!(
m.wide_adjugate_3x3_1().array,
Matrix3::new([
[Planar64Wide1::from(-11),Planar64Wide1::from(6),Planar64Wide1::from(-1)],
[Planar64Wide1::from(6),Planar64Wide1::from(-9),Planar64Wide1::from(5)],
[Planar64Wide1::from(2),Planar64Wide1::from(4),Planar64Wide1::from(-3)],
]).array
);
}

View File

@@ -1,5 +1,7 @@
mod tests;
#[cfg(feature="named-fields")]
mod named;
#[cfg(feature="fixed_wide")]
mod fixed_wide;

View File

@@ -0,0 +1,30 @@
use crate::types::{Vector3,Matrix3};
#[test]
fn test_vector(){
let mut v=Vector3::new([1,2,3]);
assert_eq!(v.x,1);
assert_eq!(v.y,2);
assert_eq!(v.z,3);
v.x=5;
assert_eq!(v.x,5);
v.y*=v.x;
assert_eq!(v.y,10);
}
#[test]
fn test_matrix(){
let mut v=Matrix3::from_value(2);
assert_eq!(v.x_axis.x,2);
assert_eq!(v.y_axis.y,2);
assert_eq!(v.z_axis.z,2);
v.x_axis.x=5;
assert_eq!(v.x_axis.x,5);
v.y_axis.z*=v.x_axis.x;
assert_eq!(v.y_axis.z,10);
}

View File

@@ -1 +1,43 @@
use crate::types::{Vector3,Matrix4x3,Matrix2x4,Matrix2x3};
#[test]
fn test_bool(){
assert_eq!(Vector3::new([false,false,false]).any(),false);
assert_eq!(Vector3::new([false,false,true]).any(),true);
assert_eq!(Vector3::new([false,false,true]).all(),false);
assert_eq!(Vector3::new([true,true,true]).all(),true);
}
#[test]
fn test_arithmetic(){
let a=Vector3::new([1,2,3]);
assert_eq!((a+a*2).array,Vector3::new([1*3,2*3,3*3]).array);
}
#[test]
fn matrix_dot(){
let rhs=Matrix2x4::new([
[ 1.0, 2.0],
[ 3.0, 4.0],
[ 5.0, 6.0],
[ 7.0, 8.0],
]); // | | |
let lhs=Matrix4x3::new([ // | | |
[1.0, 2.0, 3.0, 4.0],// [ 50.0, 60.0],
[5.0, 6.0, 7.0, 8.0],// [114.0,140.0],
[9.0,10.0,11.0,12.0],// [178.0,220.0],
]);
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
let m_dot=lhs.dot(rhs);
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
//Out[1]= {{50, 60}, {114, 140}, {178, 220}}
assert_eq!(
m_dot.array,
Matrix2x3::new([
[50.0,60.0],
[114.0,140.0],
[178.0,220.0],
]).array
);
}

View File

@@ -0,0 +1,18 @@
use crate::vector::Vector;
use crate::matrix::Matrix;
pub type Vector2<T>=Vector<2,T>;
pub type Vector3<T>=Vector<3,T>;
pub type Vector4<T>=Vector<4,T>;
pub type Matrix2<T>=Matrix<2,2,T>;
pub type Matrix2x3<T>=Matrix<2,3,T>;
pub type Matrix2x4<T>=Matrix<2,4,T>;
pub type Matrix3x2<T>=Matrix<3,2,T>;
pub type Matrix3<T>=Matrix<3,3,T>;
pub type Matrix3x4<T>=Matrix<3,4,T>;
pub type Matrix4x2<T>=Matrix<4,2,T>;
pub type Matrix4x3<T>=Matrix<4,3,T>;
pub type Matrix4<T>=Matrix<4,4,T>;

View File

@@ -1,81 +1,18 @@
// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license)
/// An array-backed vector type. Named fields are made accessible via the Deref/DerefMut traits which are implmented for 2-4 dimensions.
/// let mut v = Vector::new([1.0,2.0,3.0]);
/// v.x += v.z;
/// println!("v.x={}",v.x);
/// Vector for holding two-dimensional values.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let mut vec2 = Vector2::new(1, 2);
/// vec2 += Vector2::new(1, 2);
///
/// assert_eq!(vec2.x, 2);
/// assert_eq!(vec2.y, 4);
/// ```
pub struct Vector2<T> {
pub x: T,
pub y: T,
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
pub struct Vector<const N:usize,T>{
pub(crate) array:[T;N],
}
crate::impl_vector!();
/// Vector for holding three-dimensional values.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector3;
///
/// let mut vec3 = Vector3::new(1, 2, 3);
/// vec3 += Vector3::new(1, 2, 3);
///
/// assert_eq!(vec3.x, 2);
/// assert_eq!(vec3.y, 4);
/// assert_eq!(vec3.z, 6);
/// ```
pub struct Vector3<T> {
pub x: T,
pub y: T,
pub z: T,
}
// Needs const generics for generic case
crate::impl_vector_extend!(2);
crate::impl_vector_extend!(3);
/// Vector for holding four-dimensional values.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector4;
///
/// let mut vec4 = Vector4::new(1, 2, 3, 4);
/// vec4 += Vector4::new(1, 2, 3, 4);
///
/// assert_eq!(vec4.x, 2);
/// assert_eq!(vec4.y, 4);
/// assert_eq!(vec4.z, 6);
/// assert_eq!(vec4.w, 8);
/// ```
pub struct Vector4<T> {
pub x: T,
pub y: T,
pub z: T,
pub w: T,
}
crate::impl_vector!(Vector2 { x, y }, 2);
crate::impl_vector!(Vector3 { x, y, z }, 3);
crate::impl_vector!(Vector4 { x, y, z, w }, 4);
crate::impl_extend!(Vector2 { x, y }, Vector3, z);
crate::impl_extend!(Vector3 { x, y, z }, Vector4, w);
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );
//cross product
crate::impl_vector_3!();