Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd588d1b60 | |||
| 9da1c1ad1e | |||
| 0d5092cd84 | |||
| 8a89fcefc6 | |||
| 0c41d3182e | |||
| 85d0b3d1ac | |||
| 2da8130402 | |||
| d65fe40354 | |||
| 247987b51d | |||
| 63cf94499b | |||
| 83a39468d5 | |||
| 9aba811cd0 | |||
| e413409f9f | |||
| e6a28fbb70 | |||
| 88acec5659 | |||
| 0f0d7f7a9a | |||
| 263f0d35d4 | |||
| d713b96ad3 | |||
| 20285f0f98 | |||
| f103c247b8 | |||
| 8e1807b4b7 | |||
| f531e8d8ee | |||
| 78f860c672 | |||
| 0924518922 | |||
| 46d89619bd | |||
| 540749e4f1 | |||
| 3c5f01da89 | |||
| 70a79a8d25 | |||
| 0483c9eb27 | |||
| 61aad93f8d | |||
| cd1aa26293 | |||
| b656371142 | |||
| 9266edbf92 |
@@ -86,21 +86,6 @@ macro_rules! impl_operator {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Num,Den,Lhs> core::ops::$trait<$struct<Num,Den>> for Lhs
|
||||
where
|
||||
Den:Copy,
|
||||
Lhs:Mul<Den>,
|
||||
<Lhs as Mul<Den>>::Output:core::ops::$trait<Num>,
|
||||
{
|
||||
type Output=$struct<<<Lhs as Mul<Den>>::Output as core::ops::$trait<Num>>::Output,Den>;
|
||||
|
||||
fn $method(self,rhs:$struct<Num,Den>)->Self::Output{
|
||||
$struct{
|
||||
num:self.mul(rhs.den).$method(rhs.num),
|
||||
den:rhs.den,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! impl_assign_operator{
|
||||
|
||||
@@ -1,34 +1,41 @@
|
||||
use bnum::{BInt,cast::As};
|
||||
use typenum::Unsigned;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash)]
|
||||
pub struct Fixed<const CHUNKS:usize,Frac>{
|
||||
pub(crate)bits:BInt<{CHUNKS}>,
|
||||
pub(crate)frac:PhantomData<Frac>,
|
||||
pub(crate)frac:std::marker::PhantomData<Frac>,
|
||||
}
|
||||
|
||||
impl<const CHUNKS:usize,Frac:Unsigned> Fixed<CHUNKS,Frac>{
|
||||
pub const MAX:Self=Self{bits:BInt::<CHUNKS>::MAX,frac:PhantomData};
|
||||
pub const MIN:Self=Self{bits:BInt::<CHUNKS>::MIN,frac:PhantomData};
|
||||
pub const ZERO:Self=Self{bits:BInt::<CHUNKS>::ZERO,frac:PhantomData};
|
||||
pub const EPSILON:Self=Self{bits:BInt::<CHUNKS>::ONE,frac:PhantomData};
|
||||
pub const NEG_EPSILON:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE,frac:PhantomData};
|
||||
pub const ONE:Self=Self{bits:BInt::<CHUNKS>::ONE.shl(Frac::U32),frac:PhantomData};
|
||||
pub const TWO:Self=Self{bits:BInt::<CHUNKS>::TWO.shl(Frac::U32),frac:PhantomData};
|
||||
pub const HALF:Self=Self{bits:BInt::<CHUNKS>::ONE.shl(Frac::U32-1),frac:PhantomData};
|
||||
pub const NEG_ONE:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32),frac:PhantomData};
|
||||
pub const NEG_TWO:Self=Self{bits:BInt::<CHUNKS>::NEG_TWO.shl(Frac::U32),frac:PhantomData};
|
||||
pub const NEG_HALF:Self=Self{bits:BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32-1),frac:PhantomData};
|
||||
pub const MAX:Self=Self::from_bits(BInt::<CHUNKS>::MAX);
|
||||
pub const MIN:Self=Self::from_bits(BInt::<CHUNKS>::MIN);
|
||||
pub const ZERO:Self=Self::from_bits(BInt::<CHUNKS>::ZERO);
|
||||
pub const EPSILON:Self=Self::from_bits(BInt::<CHUNKS>::ONE);
|
||||
pub const NEG_EPSILON:Self=Self::from_bits(BInt::<CHUNKS>::NEG_ONE);
|
||||
pub const ONE:Self=Self::from_bits(BInt::<CHUNKS>::ONE.shl(Frac::U32));
|
||||
pub const TWO:Self=Self::from_bits(BInt::<CHUNKS>::TWO.shl(Frac::U32));
|
||||
pub const HALF:Self=Self::from_bits(BInt::<CHUNKS>::ONE.shl(Frac::U32-1));
|
||||
pub const NEG_ONE:Self=Self::from_bits(BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32));
|
||||
pub const NEG_TWO:Self=Self::from_bits(BInt::<CHUNKS>::NEG_TWO.shl(Frac::U32));
|
||||
pub const NEG_HALF:Self=Self::from_bits(BInt::<CHUNKS>::NEG_ONE.shl(Frac::U32-1));
|
||||
}
|
||||
impl<const CHUNKS:usize,Frac> Fixed<CHUNKS,Frac>{
|
||||
#[inline]
|
||||
pub const fn from_bits(bits:BInt::<CHUNKS>)->Self{
|
||||
Self{
|
||||
bits,
|
||||
frac:PhantomData,
|
||||
frac:std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub const fn to_bits(self)->BInt<CHUNKS>{
|
||||
self.bits
|
||||
}
|
||||
#[inline]
|
||||
pub const fn raw(value:i64)->Self{
|
||||
Self::from_bits(BInt::from_bits(bnum::BUint::from_digit(value as u64)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const CHUNKS:usize,Frac:Unsigned,T> From<T> for Fixed<CHUNKS,Frac>
|
||||
@@ -36,10 +43,7 @@ impl<const CHUNKS:usize,Frac:Unsigned,T> From<T> for Fixed<CHUNKS,Frac>
|
||||
BInt<CHUNKS>:From<T>
|
||||
{
|
||||
fn from(value:T)->Self{
|
||||
Self{
|
||||
bits:BInt::<{CHUNKS}>::from(value)<<Frac::U32,
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(BInt::<{CHUNKS}>::from(value)<<Frac::U32)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +68,7 @@ impl<const CHUNKS:usize,Frac> Ord for Fixed<CHUNKS,Frac>{
|
||||
impl<const CHUNKS:usize,Frac> std::ops::Neg for Fixed<CHUNKS,Frac>{
|
||||
type Output=Self;
|
||||
fn neg(self)->Self{
|
||||
Self{
|
||||
bits:self.bits.neg(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(self.bits.neg())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,10 +78,7 @@ macro_rules! impl_additive_operator {
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: Self) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(other.bits),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(self.bits.$method(other.bits))
|
||||
}
|
||||
}
|
||||
impl<const CHUNKS:usize,Frac:Unsigned,U> core::ops::$trait<U> for $struct<CHUNKS,Frac>
|
||||
@@ -90,10 +88,7 @@ macro_rules! impl_additive_operator {
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: U) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(self.bits.$method(BInt::<CHUNKS>::from(other)<<Frac::U32))
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -141,10 +136,7 @@ macro_rules! impl_multiply_operator_const {
|
||||
//this can be done better but that is a job for later
|
||||
let lhs=self.bits.as_::<BInt::<{$width*2}>>();
|
||||
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
|
||||
Self {
|
||||
bits:lhs.mul(rhs).shr(Frac::U32).as_(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(lhs.mul(rhs).shr(Frac::U32).as_())
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -169,10 +161,7 @@ macro_rules! impl_divide_operator_const {
|
||||
//this only needs to be $width+Frac::U32/64+1 but MUH CONST GENERICS!!!!!
|
||||
let lhs=self.bits.as_::<BInt::<{$width*2}>>().shl(Frac::U32);
|
||||
let rhs=other.bits.as_::<BInt::<{$width*2}>>();
|
||||
Self {
|
||||
bits:lhs.div(rhs).as_(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(lhs.div(rhs).as_())
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -196,10 +185,7 @@ macro_rules! impl_multiplicatave_operator {
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: U) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(BInt::<CHUNKS>::from(other)),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(self.bits.$method(BInt::<CHUNKS>::from(other)))
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -273,10 +259,7 @@ macro_rules! impl_shift_operator {
|
||||
type Output = $output;
|
||||
|
||||
fn $method(self, other: u32) -> Self::Output {
|
||||
Self {
|
||||
bits:self.bits.$method(other),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Self::from_bits(self.bits.$method(other))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@ use bnum::cast::As;
|
||||
use typenum::{Sum,Unsigned};
|
||||
use crate::fixed::Fixed;
|
||||
use fixed_wide_traits::wide::WideMul;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
macro_rules! impl_wide_mul {
|
||||
($lhs: expr,$rhs: expr) => {
|
||||
@@ -14,10 +13,7 @@ macro_rules! impl_wide_mul {
|
||||
{
|
||||
type Output=Fixed<{$lhs+$rhs},Sum<A,B>>;
|
||||
fn wide_mul(self,rhs:Fixed<$rhs,B>)->Self::Output{
|
||||
Fixed{
|
||||
bits:self.bits.as_::<BInt<{$lhs+$rhs}>>()*rhs.bits.as_::<BInt<{$lhs+$rhs}>>(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Fixed::from_bits(self.bits.as_::<BInt<{$lhs+$rhs}>>()*rhs.bits.as_::<BInt<{$lhs+$rhs}>>())
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -44,10 +40,7 @@ impl_wide_mul_all!(
|
||||
);
|
||||
impl<const SRC:usize,Frac> Fixed<SRC,Frac>{
|
||||
pub fn widen<const DST:usize>(self)->Fixed<DST,Frac>{
|
||||
Fixed{
|
||||
bits:self.bits.as_::<BInt<DST>>(),
|
||||
frac:PhantomData,
|
||||
}
|
||||
Fixed::from_bits(self.bits.as_::<BInt<DST>>())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,42 +50,26 @@ impl<const CHUNKS:usize,Frac:Unsigned> Fixed<CHUNKS,Frac>
|
||||
<Fixed::<CHUNKS,Frac> as WideMul>::Output:Ord,
|
||||
{
|
||||
pub fn sqrt_unchecked(self)->Self{
|
||||
//pow2 must be the minimum power of two which when squared is greater than self
|
||||
//the algorithm:
|
||||
//1. count "used" bits to the left of the decimal
|
||||
//2. add one
|
||||
//This is the power of two which is greater than self.
|
||||
//3. divide by 2 via >>1
|
||||
//4. add on fractional offset
|
||||
//1<<max_shift must be the minimum power of two which when squared is greater than self
|
||||
//calculating max_shift:
|
||||
//1. count "used" bits to the left of the decimal, not including the sign bit (so -1)
|
||||
//2. divide by 2 via >>1 (sqrt-ish)
|
||||
//3. add on fractional offset
|
||||
//Voila
|
||||
//0001.0000 Fixed<u8,4>
|
||||
//sqrt
|
||||
//0110.0000
|
||||
//pow2 = 0100.0000
|
||||
let mut pow2=Self{
|
||||
bits:BInt::<CHUNKS>::ONE.shl(((((CHUNKS as i32*64-Frac::I32-(self.bits.leading_zeros() as i32)+1)>>1)+Frac::I32) as u32).saturating_sub(1)),
|
||||
frac:PhantomData,
|
||||
};
|
||||
let mut result=pow2;
|
||||
let used_bits=self.bits.bits() as i32-1-Frac::I32;
|
||||
let max_shift=((used_bits>>1)+Frac::I32) as u32;
|
||||
let mut result=Self::ZERO;
|
||||
|
||||
//cheat to make the types match
|
||||
//multiply by one to make the types match (hack)
|
||||
let wide_self=self.wide_mul(Fixed::<CHUNKS,Frac>::ONE);
|
||||
loop{
|
||||
//TODO: closed loop over bit shift exponent rather than pow2
|
||||
if pow2==Self::ZERO{
|
||||
break result;
|
||||
//descend down the bits and check if flipping each bit would push the square over the input value
|
||||
for shift in (0..=max_shift).rev(){
|
||||
let new_result=result|Fixed::<CHUNKS,Frac>::from_bits(BInt::from_bits(bnum::BUint::power_of_two(shift)));
|
||||
if new_result.wide_mul(new_result)<=wide_self{
|
||||
result=new_result;
|
||||
}
|
||||
//TODO: flip a single bit instead of adding a power of 2
|
||||
let new_result=result+pow2;
|
||||
//note that the implicit truncation in the multiply
|
||||
//means that the algorithm can return a result which squares to a number greater than the input.
|
||||
match wide_self.cmp(&new_result.wide_mul(new_result)){
|
||||
core::cmp::Ordering::Less=>(),
|
||||
core::cmp::Ordering::Equal=>break new_result,
|
||||
core::cmp::Ordering::Greater=>result=new_result,
|
||||
}
|
||||
pow2>>=1;
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn sqrt(self)->Self{
|
||||
if self<Self::ZERO{
|
||||
|
||||
@@ -20,6 +20,11 @@ fn test_sqrt(){
|
||||
assert_eq!(a.sqrt(),I32F32::from(2));
|
||||
}
|
||||
#[test]
|
||||
fn test_sqrt_zero(){
|
||||
let a=I32F32::ZERO;
|
||||
assert_eq!(a.sqrt(),I32F32::ZERO);
|
||||
}
|
||||
#[test]
|
||||
fn test_sqrt_low(){
|
||||
let a=I32F32::HALF;
|
||||
let b=a*a;
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
use std::ops::Add;
|
||||
use fixed_wide_traits::wide::WideDot;
|
||||
|
||||
//TODO: replace this with 4x3 matrix
|
||||
// mat4x3.wide_dot(vec3.extend(1))
|
||||
|
||||
pub struct Affine<M,T>{
|
||||
pub matrix:M,
|
||||
pub offset:T,
|
||||
}
|
||||
|
||||
impl<M:Copy,T:Copy> Affine<M,T>{
|
||||
pub fn wide_transform<X>(&self,input:X)-><<M as WideDot<X>>::Output as Add<T>>::Output
|
||||
where
|
||||
M:WideDot<X>,
|
||||
<M as WideDot<X>>::Output:Add<T>,
|
||||
{
|
||||
self.matrix.wide_dot(input)+self.offset
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
mod macros;
|
||||
mod vector;
|
||||
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
pub mod affine;
|
||||
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(test)]
|
||||
mod tests;
|
||||
|
||||
102
fixed_wide_vectors/src/macros/common.rs
Normal file
102
fixed_wide_vectors/src/macros/common.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_common {
|
||||
( $struct: ident { $($field: ident), + }, ( $($generic: 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 its values as a tuple.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(0, 0);
|
||||
/// let tuple = vec2.to_tuple();
|
||||
///
|
||||
/// assert_eq!(tuple, (0, 0));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn to_tuple(self) -> ( $($generic), + ) {
|
||||
( $(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 ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
185
fixed_wide_vectors/src/macros/matrix.rs
Normal file
185
fixed_wide_vectors/src/macros/matrix.rs
Normal file
@@ -0,0 +1,185 @@
|
||||
// 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),
|
||||
( $($generic_outer: tt), + )
|
||||
) => {
|
||||
$crate::impl_common!($struct_outer { $($field_outer), + }, ( $($generic_outer), + ), $size_outer);
|
||||
impl<U> $struct_outer<U> {
|
||||
#[inline(always)]
|
||||
pub fn to_vector(self) -> $vector_outer<U> {
|
||||
$vector_outer {
|
||||
$(
|
||||
$vector_field_outer: self.$field_outer
|
||||
), +
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[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),
|
||||
( $($generic_outer: tt), + )
|
||||
) => {
|
||||
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(always)]
|
||||
pub fn to_tuple_2d(self) -> ( $($generic_outer), + ) {
|
||||
( $(self.$field_outer.to_tuple()), + )
|
||||
}
|
||||
|
||||
#[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), + }, $vector_outer { $($vector_field_outer), + }, $size_outer),
|
||||
($struct_inner { $($field_inner), + }, $matrix_inner { $($matrix_field_inner), + }, $size_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
|
||||
), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
macro_rules! nested {
|
||||
(($($f:ident),*) $args:tt) => {
|
||||
$(nested!(@call $f $args);)*
|
||||
};
|
||||
(@call $f:ident ($($arg:expr),*)) => {
|
||||
$f($($arg),*);
|
||||
};
|
||||
}
|
||||
|
||||
nested! {
|
||||
(show1, show2)
|
||||
(a, b, c)
|
||||
}
|
||||
*/
|
||||
|
||||
#[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) ); +
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,291 +1,6 @@
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
pub mod wide;
|
||||
|
||||
// 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), + }, ( $($generic: 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 its values as a tuple.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use fixed_wide_vectors::Vector2;
|
||||
///
|
||||
/// let vec2 = Vector2::new(0, 0);
|
||||
/// let tuple = vec2.to_tuple();
|
||||
///
|
||||
/// assert_eq!(tuple, (0, 0));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn to_tuple(self) -> ( $($generic), + ) {
|
||||
( $(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> From<($($generic), +)> for $struct<T> {
|
||||
fn from(from: ($($generic), +)) -> Self {
|
||||
let ( $($field), + ) = from;
|
||||
|
||||
Self {
|
||||
$( $field ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> $struct<T> {
|
||||
pub fn min(self, rhs: Self) -> $struct<T> {
|
||||
$struct{
|
||||
$( $field: self.$field.min(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn max(self, rhs: Self) -> $struct<T> {
|
||||
$struct{
|
||||
$( $field: self.$field.max(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn cmp(self, rhs: Self) -> $struct<core::cmp::Ordering> {
|
||||
$struct{
|
||||
$( $field: self.$field.cmp(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn lt(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.lt(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
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 $struct<bool>{
|
||||
pub fn all(&self)->bool{
|
||||
const ALL:[bool;$size]=[true;$size];
|
||||
core::matches!(self.to_array(),ALL)
|
||||
}
|
||||
pub fn any(&self)->bool{
|
||||
$( self.$field )|| +
|
||||
}
|
||||
}
|
||||
|
||||
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 arithmetic pperators
|
||||
$crate::impl_operator!( $struct { $($field), + }, AddAssign, add_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Add, add, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, SubAssign, sub_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Sub, sub, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, MulAssign, mul_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Mul, mul, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, DivAssign, div_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Div, div, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, RemAssign, rem_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, Rem, rem, Self );
|
||||
|
||||
// Impl bitwise operators
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitAndAssign, bitand_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitAnd, bitand, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitOrAssign, bitor_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitOr, bitor, Self );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitXorAssign, bitxor_assign );
|
||||
$crate::impl_operator!( $struct { $($field), + }, BitXor, bitxor, Self );
|
||||
|
||||
// Impl floating-point based methods
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
$crate::impl_wide_operations!( $struct { $($field), + }, $size );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_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) ); +
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
pub mod common;
|
||||
pub mod vector;
|
||||
pub mod matrix;
|
||||
|
||||
209
fixed_wide_vectors/src/macros/vector.rs
Normal file
209
fixed_wide_vectors/src/macros/vector.rs
Normal file
@@ -0,0 +1,209 @@
|
||||
// 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), + }, ( $($generic: ident), + ), $size: expr ) => {
|
||||
$crate::impl_common!($struct { $($field), + }, ( $($generic), + ), $size);
|
||||
|
||||
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> From<($($generic), +)> for $struct<T> {
|
||||
fn from(from: ($($generic), +)) -> Self {
|
||||
let ( $($field), + ) = from;
|
||||
|
||||
Self {
|
||||
$( $field ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> $struct<T> {
|
||||
pub fn min(self, rhs: Self) -> $struct<T> {
|
||||
$struct{
|
||||
$( $field: self.$field.min(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn max(self, rhs: Self) -> $struct<T> {
|
||||
$struct{
|
||||
$( $field: self.$field.max(rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn cmp(self, rhs: Self) -> $struct<core::cmp::Ordering> {
|
||||
$struct{
|
||||
$( $field: self.$field.cmp(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
pub fn lt(self, rhs: Self) -> $struct<bool> {
|
||||
$struct{
|
||||
$( $field: self.$field.lt(&rhs.$field) ), +
|
||||
}
|
||||
}
|
||||
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 $struct<bool>{
|
||||
pub fn all(&self)->bool{
|
||||
const ALL:[bool;$size]=[true;$size];
|
||||
core::matches!(self.to_array(),ALL)
|
||||
}
|
||||
pub fn any(&self)->bool{
|
||||
$( self.$field )|| +
|
||||
}
|
||||
}
|
||||
|
||||
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 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 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 );
|
||||
|
||||
// Impl floating-point based methods
|
||||
#[cfg(feature="fixed_wide_traits")]
|
||||
$crate::impl_wide_vector_operations!( $struct { $($field), + }, $size );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#[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) ), +
|
||||
}
|
||||
}
|
||||
}
|
||||
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) ); +
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_wide_operations {
|
||||
macro_rules! impl_wide_vector_operations {
|
||||
( $struct: ident { $($field: ident), + }, $size: expr ) => {
|
||||
//this one is shared between vec and mat
|
||||
impl<U,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> fixed_wide_traits::wide::WideMul for $struct<T> {
|
||||
type Output=$struct<U>;
|
||||
#[inline]
|
||||
@@ -11,6 +12,7 @@ macro_rules! impl_wide_operations {
|
||||
}
|
||||
}
|
||||
}
|
||||
//these ones are vec only
|
||||
impl<V:core::ops::Add<Output=V>,U,T:fixed_wide_traits::wide::WideMul<U,Output=V>> fixed_wide_traits::wide::WideDot<$struct<U>> for $struct<T> {
|
||||
type Output=V;
|
||||
#[inline]
|
||||
@@ -31,6 +33,57 @@ macro_rules! impl_wide_operations {
|
||||
};
|
||||
}
|
||||
|
||||
// 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_wide_matrix_mul {
|
||||
(
|
||||
($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)
|
||||
) => {
|
||||
impl<T,U> fixed_wide_traits::wide::WideDot<$matrix_inner<$rhs_struct_inner<U>>> for $struct_outer<$struct_inner<T>>
|
||||
where
|
||||
$struct_inner<T>:fixed_wide_traits::wide::WideDot<$rhs_struct_inner<U>>,
|
||||
{
|
||||
type Output=$struct_outer<<$struct_inner<T> as fixed_wide_traits::wide::WideDot<$rhs_struct_inner<U>>::Output>;
|
||||
#[inline]
|
||||
fn wide_dot(self,rhs:$matrix_inner<$rhs_struct_inner<U>>)->Self::Output{
|
||||
//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(trax)
|
||||
).to_vector()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! impl_wide_matrix_operations {
|
||||
(
|
||||
($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> {
|
||||
#[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
|
||||
|
||||
34
fixed_wide_vectors/src/matrix.rs
Normal file
34
fixed_wide_vectors/src/matrix.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use crate::{Vector2,Vector3,Vector4};
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
crate::impl_matrix!((Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2), (T, T));
|
||||
crate::impl_matrix!((Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3), (T, T, T));
|
||||
crate::impl_matrix!((Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4), (T, T, T, T));
|
||||
|
||||
crate::impl_extend!(Matrix2 { x_axis, y_axis }, Matrix3, z_axis);
|
||||
crate::impl_extend!(Matrix3 { x_axis, y_axis, z_axis }, Matrix4, w_axis);
|
||||
|
||||
crate::impl_matrix_inner!((Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2), (Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2), ((T, T), (T, T)) );
|
||||
crate::impl_matrix_inner!((Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2), (Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3), ((T, T, T), (T, T, T)) );
|
||||
crate::impl_matrix_inner!((Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2), (Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4), ((T, T, T, T), (T, T, T, T)) );
|
||||
crate::impl_matrix_inner!((Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3), (Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2), ((T, T), (T, T), (T, T)) );
|
||||
crate::impl_matrix_inner!((Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3), (Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3), ((T, T, T), (T, T, T), (T, T, T)) );
|
||||
crate::impl_matrix_inner!((Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3), (Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4), ((T, T, T, T), (T, T, T, T), (T, T, T, T)) );
|
||||
crate::impl_matrix_inner!((Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4), (Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2), ((T, T), (T, T), (T, T), (T, T)) );
|
||||
crate::impl_matrix_inner!((Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4), (Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3), ((T, T, T), (T, T, T), (T, T, T), (T, T, T)) );
|
||||
crate::impl_matrix_inner!((Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4), (Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4), ((T, T, T, T), (T, T, T, T), (T, T, T, T), (T, T, T, T)) );
|
||||
@@ -1,10 +1,10 @@
|
||||
use fixed_wide_traits::wide::WideMul;
|
||||
use fixed_wide_traits::wide::WideDot;
|
||||
|
||||
use crate::Vector3;
|
||||
use crate::{Vector2,Vector3,Matrix3};
|
||||
|
||||
type Planar64=fixed_wide::types::I32F32;
|
||||
//type Planar64Wide1=fixed::types::I64F64;
|
||||
type Planar64Wide1=fixed_wide::types::I64F64;
|
||||
//type Planar64Wide2=fixed_wide::types::I128F128;
|
||||
type Planar64Wide3=fixed_wide::types::I256F256;
|
||||
|
||||
@@ -49,3 +49,20 @@ fn wide_vec3_length_squared(){
|
||||
|
||||
assert_eq!(v3,Planar64Wide3::from(3i128.pow(8)*3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_vec_of_vec_dot(){
|
||||
let vv=Vector3::<Vector2<_>>::from_value_2d(Planar64::from(3));
|
||||
// do the dot product of the inner vectors multiplied component wise
|
||||
// this lowers the rank of the data structure and is kind of a weird operation lol
|
||||
let vv_dot=vv.wide_dot(vv);
|
||||
assert_eq!(vv_dot,Vector2::from_value(Planar64Wide1::from(3i128.pow(3))));
|
||||
}
|
||||
#[test]
|
||||
fn wide_matrix_dot(){
|
||||
let m=Matrix3::<Vector3<_>>::from_value_2d(Planar64::from(3));
|
||||
//normal matrix product
|
||||
todo!()
|
||||
//let m_dot=m.wide_dot(m);
|
||||
//assert_eq!(m_dot,Matrix3::<Vector3<_>>::from_value_2d(Planar64Wide1::from(3i128.pow(2))));
|
||||
}
|
||||
|
||||
@@ -66,3 +66,16 @@ pub struct Vector4<T> {
|
||||
crate::impl_vector!(Vector2 { x, y }, (T, T), 2);
|
||||
crate::impl_vector!(Vector3 { x, y, z }, (T, T, T), 3);
|
||||
crate::impl_vector!(Vector4 { x, y, z, w }, (T, T, T, T), 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), ((T, T), (T, T)) );
|
||||
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3), ((T, T, T), (T, T, T)) );
|
||||
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), ((T, T, T, T), (T, T, T, T)) );
|
||||
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector2 { x, y }, Vector2 { x, y }, 2), ((T, T), (T, T), (T, T)) );
|
||||
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3), ((T, T, T), (T, T, T), (T, T, T)) );
|
||||
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), ((T, T, T, T), (T, T, T, T), (T, T, T, T)) );
|
||||
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector2 { x, y }, Vector2 { x, y }, 2), ((T, T), (T, T), (T, T), (T, T)) );
|
||||
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3), ((T, T, T), (T, T, T), (T, T, T), (T, T, T)) );
|
||||
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), ((T, T, T, T), (T, T, T, T), (T, T, T, T), (T, T, T, T)) );
|
||||
|
||||
Reference in New Issue
Block a user