pub const trait LerpUtil { fn lerp(self, from: Self, to: Self) -> Self; } const impl LerpUtil for f32 { /// linear interpolation /// from * (1.0 - self) + to * self fn lerp(self, from: Self, to: Self) -> Self { from + (to - from) * self } } macro_rules! impl_op { ($T:ident $op:ident $fn:ident $opa:ident $fna:ident; $($field:ident)*) => { #[allow(non_snake_case)] mod ${concat($T, _op_, $fn, _impl)} { use super::*; #[allow(unused_imports)] use std::ops::*; const impl $op for $T { type Output = Self; fn $fn(self, rhs: Self) -> Self::Output { Self { $($field: self.$field.$fn(rhs.$field),)* } } } const impl $opa for $T { fn $fna(&mut self, rhs: Self) { *self = self.$fn(rhs); } } const impl $op for $T { type Output = Self; fn $fn(self, rhs: f32) -> Self::Output { Self { $($field: self.$field.$fn(rhs),)* } } } const impl $op<$T> for f32 { type Output = $T; fn $fn(self, rhs: $T) -> Self::Output { $T { $($field: self.$fn(rhs.$field),)* } } } const impl $opa for $T { fn $fna(&mut self, rhs: f32) { *self = self.$fn(rhs); } } } }; // Without the `f32` operations, for a type whose fields are not all the // same kind of number: there is nothing a bare float means to a fraction // and an offset at once. (same $T:ident $op:ident $fn:ident $opa:ident $fna:ident; $($field:ident)*) => { #[allow(non_snake_case)] mod ${concat($T, _op_, $fn, _same_impl)} { use super::*; #[allow(unused_imports)] use std::ops::*; const impl $op for $T { type Output = Self; fn $fn(self, rhs: Self) -> Self::Output { Self { $($field: self.$field.$fn(rhs.$field),)* } } } const impl $opa for $T { fn $fna(&mut self, rhs: Self) { *self = self.$fn(rhs); } } } }; (same $T:ident $op:ident $fn:ident; $($field:ident)*) => { impl_op!(same $T $op $fn ${concat($op,Assign)} ${concat($fn,_assign)}; $($field)*); }; ($T:ident $op:ident $fn:ident; $($field:ident)*) => { impl_op!($T $op $fn ${concat($op,Assign)} ${concat($fn,_assign)}; $($field)*); }; (impl $op:ident for $T:ident: $fn:ident $($field:ident)*) => { impl_op!($T $op $fn ${concat($op,Assign)} ${concat($fn,_assign)}; $($field)*); }; } pub(crate) use impl_op;