use super::*;
use compile_time_integer::*;
#[rustfmt::skip]
pub mod dimension_aliases;
pub use dimension_aliases::*;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Time(i64);
impl Time {
pub const ZERO: Self = Time(0);
pub const fn from_nanoseconds(value: i64) -> Self {
Self(value)
}
pub const fn from_seconds_f32(value: f32) -> Self {
Self((value * 1_000_000_000.0) as i64)
}
pub fn from_seconds(value: Second<f32>) -> Self {
Self::from_seconds_f32(value.into_inner())
}
pub const fn as_nanoseconds(self) -> i64 {
self.0
}
pub const fn as_seconds_f32(self) -> f32 {
(self.0 as f32) / 1_000_000_000.0
}
pub const fn as_seconds(self) -> Second<f32> {
Second::new(self.as_seconds_f32())
}
}
impl From<Second<f32>> for Time {
fn from(was: Second<f32>) -> Self {
Self::from_seconds(was)
}
}
impl From<Time> for Second<f32> {
fn from(was: Time) -> Self {
was.as_seconds()
}
}
impl Add for Time {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
}
impl AddAssign for Time {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for Time {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0)
}
}
impl SubAssign for Time {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Neg for Time {
type Output = Self;
fn neg(self) -> Self {
Self(-self.0)
}
}
impl Mul<DimensionlessInteger> for Time {
type Output = Self;
fn mul(self, rhs: DimensionlessInteger) -> Self {
Self(self.0 * rhs.0)
}
}
impl MulAssign<DimensionlessInteger> for Time {
fn mul_assign(&mut self, rhs: DimensionlessInteger) {
self.0 *= rhs.0;
}
}
impl Div<DimensionlessInteger> for Time {
type Output = Self;
fn div(self, rhs: DimensionlessInteger) -> Self {
Self(self.0 / rhs.0)
}
}
impl DivAssign<DimensionlessInteger> for Time {
fn div_assign(&mut self, rhs: DimensionlessInteger) {
self.0 /= rhs.0;
}
}
impl Mul<f32> for Time {
type Output = f32;
fn mul(self, rhs: f32) -> f32 {
self.as_seconds_f32() * rhs
}
}
impl Mul<Time> for f32 {
type Output = Self;
fn mul(self, rhs: Time) -> Self {
self * rhs.as_seconds_f32()
}
}
impl Div<f32> for Time {
type Output = f32;
fn div(self, rhs: f32) -> f32 {
self.as_seconds_f32() / rhs
}
}
impl Div<Time> for f32 {
type Output = Self;
fn div(self, rhs: Time) -> Self {
self / rhs.as_seconds_f32()
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct DimensionlessInteger(pub i64);
impl DimensionlessInteger {
#[inline]
pub const fn new(value: i64) -> Self {
Self(value)
}
#[inline]
pub const fn const_eq(&self, rhs: &Self) -> bool {
self.0 == rhs.0
}
#[inline]
pub const fn is_zero(&self) -> bool {
self.0 == 0
}
}
impl From<i64> for DimensionlessInteger {
fn from(was: i64) -> Self {
Self(was)
}
}
impl From<DimensionlessInteger> for i64 {
fn from(was: DimensionlessInteger) -> Self {
was.0
}
}
impl Add for DimensionlessInteger {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
}
impl AddAssign for DimensionlessInteger {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for DimensionlessInteger {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0)
}
}
impl SubAssign for DimensionlessInteger {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Mul for DimensionlessInteger {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self(self.0 * rhs.0)
}
}
impl MulAssign for DimensionlessInteger {
fn mul_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
}
impl Div for DimensionlessInteger {
type Output = DimensionlessFraction;
fn div(self, rhs: Self) -> DimensionlessFraction {
assert_ne!(rhs, Self::new(0));
DimensionlessFraction(self, rhs)
}
}
impl Neg for DimensionlessInteger {
type Output = Self;
fn neg(self) -> Self {
Self(-self.0)
}
}
impl Mul<Time> for DimensionlessInteger {
type Output = Time;
fn mul(self, rhs: Time) -> Time {
Time(self.0 * rhs.0)
}
}
#[macro_export]
macro_rules! dimensionless_fraction {
($num: expr, $denom: expr) => {
DimensionlessFraction::new(DimensionlessInteger($num), DimensionlessInteger($denom))
};
}
pub use dimensionless_fraction;
#[macro_export]
macro_rules! dimensionless_fraction_unchecked {
($num: expr, $denom: expr) => {
DimensionlessFraction::new_unchecked(
DimensionlessInteger($num),
DimensionlessInteger($denom),
)
};
}
pub use dimensionless_fraction_unchecked;
#[derive(Clone, Copy, Debug)]
pub struct DimensionlessFraction(DimensionlessInteger, DimensionlessInteger);
impl DimensionlessFraction {
#[inline]
pub const fn is_valid(&self) -> bool {
!self.1.is_zero()
}
#[inline]
pub const fn new(num: DimensionlessInteger, denom: DimensionlessInteger) -> Self {
let new = Self(num, denom);
if new.is_valid() {
new
} else {
panic!("attempted to construct a DimensionlessFraction with a zero denominator");
}
}
#[inline]
pub const fn new_unchecked(num: DimensionlessInteger, denom: DimensionlessInteger) -> Self {
Self(num, denom)
}
#[inline]
pub const fn reciprocal(&self) -> Self {
Self::new(self.1, self.0)
}
#[inline]
pub const fn reciprocal_unchecked(&self) -> Self {
Self(self.1, self.0)
}
#[inline]
pub const fn into_components(self) -> (DimensionlessInteger, DimensionlessInteger) {
(self.0, self.1)
}
#[inline]
pub const fn as_f32(&self) -> f32 {
self.0.0 as f32 / self.1.0 as f32
}
#[inline]
pub const fn as_f64(&self) -> f64 {
self.0.0 as f64 / self.1.0 as f64
}
#[inline]
pub const fn as_quantity_f32(&self) -> Dimensionless<f32> {
Dimensionless::new(self.as_f32())
}
#[inline]
pub const fn as_quantity_f64(&self) -> Dimensionless<f64> {
Dimensionless::new(self.as_f64())
}
}
impl From<DimensionlessInteger> for DimensionlessFraction {
fn from(was: DimensionlessInteger) -> Self {
Self(was, DimensionlessInteger::new(1))
}
}
impl Ord for DimensionlessFraction {
fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
let a = self.0 * rhs.1;
let b = self.1 * rhs.0;
a.cmp(&b)
}
}
impl PartialEq for DimensionlessFraction {
fn eq(&self, rhs: &Self) -> bool {
self.cmp(rhs) == core::cmp::Ordering::Equal
}
}
impl Eq for DimensionlessFraction {}
impl PartialOrd for DimensionlessFraction {
fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(rhs))
}
}
impl Neg for DimensionlessFraction {
type Output = Self;
fn neg(self) -> Self {
Self(-self.0, self.1)
}
}
impl Mul for DimensionlessFraction {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self(self.0 * rhs.0, self.1 * rhs.1)
}
}
impl MulAssign for DimensionlessFraction {
fn mul_assign(&mut self, rhs: Self) {
*self = *self * rhs;
}
}
impl Div for DimensionlessFraction {
type Output = Self;
fn div(self, rhs: Self) -> Self {
self * rhs.reciprocal()
}
}
impl DivAssign for DimensionlessFraction {
fn div_assign(&mut self, rhs: Self) {
*self = *self / rhs;
}
}
impl Add for DimensionlessFraction {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self(self.0 * rhs.1 + rhs.0 * self.1, self.1 * rhs.1)
}
}
impl AddAssign for DimensionlessFraction {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl Sub for DimensionlessFraction {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self + -rhs
}
}
impl SubAssign for DimensionlessFraction {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl Mul<DimensionlessInteger> for DimensionlessFraction {
type Output = Self;
fn mul(self, rhs: DimensionlessInteger) -> Self {
Self(self.0 * rhs, self.1)
}
}
impl MulAssign<DimensionlessInteger> for DimensionlessFraction {
fn mul_assign(&mut self, rhs: DimensionlessInteger) {
*self = *self * rhs;
}
}
impl Div<DimensionlessInteger> for DimensionlessFraction {
type Output = Self;
fn div(self, rhs: DimensionlessInteger) -> Self {
Self(self.0, self.1 * rhs)
}
}
impl DivAssign<DimensionlessInteger> for DimensionlessFraction {
fn div_assign(&mut self, rhs: DimensionlessInteger) {
*self = *self / rhs;
}
}
impl Add<DimensionlessInteger> for DimensionlessFraction {
type Output = Self;
fn add(self, rhs: DimensionlessInteger) -> Self {
self + Self::from(rhs)
}
}
impl AddAssign<DimensionlessInteger> for DimensionlessFraction {
fn add_assign(&mut self, rhs: DimensionlessInteger) {
*self = *self + rhs;
}
}
impl Sub<DimensionlessInteger> for DimensionlessFraction {
type Output = Self;
fn sub(self, rhs: DimensionlessInteger) -> Self {
self + Self::from(-rhs)
}
}
impl SubAssign<DimensionlessInteger> for DimensionlessFraction {
fn sub_assign(&mut self, rhs: DimensionlessInteger) {
*self = *self - rhs;
}
}
impl Mul<Time> for DimensionlessFraction {
type Output = Time;
fn mul(self, rhs: Time) -> Time {
rhs * self.0 / self.1
}
}
impl Mul<DimensionlessFraction> for DimensionlessInteger {
type Output = DimensionlessFraction;
fn mul(self, rhs: DimensionlessFraction) -> DimensionlessFraction {
rhs * self
}
}
impl Div<DimensionlessFraction> for DimensionlessInteger {
type Output = DimensionlessFraction;
fn div(self, rhs: DimensionlessFraction) -> DimensionlessFraction {
self * rhs.reciprocal()
}
}
impl Mul<DimensionlessFraction> for Time {
type Output = Self;
fn mul(self, rhs: DimensionlessFraction) -> Self {
rhs * self
}
}
impl MulAssign<DimensionlessFraction> for Time {
fn mul_assign(&mut self, rhs: DimensionlessFraction) {
*self = *self * rhs;
}
}
impl Div<DimensionlessFraction> for Time {
type Output = Self;
fn div(self, rhs: DimensionlessFraction) -> Self {
self * rhs.reciprocal()
}
}
impl DivAssign<DimensionlessFraction> for Time {
fn div_assign(&mut self, rhs: DimensionlessFraction) {
*self = *self / rhs;
}
}
impl Add<DimensionlessFraction> for DimensionlessInteger {
type Output = DimensionlessFraction;
fn add(self, rhs: DimensionlessFraction) -> DimensionlessFraction {
rhs + self
}
}
impl Sub<DimensionlessFraction> for DimensionlessInteger {
type Output = DimensionlessFraction;
fn sub(self, rhs: DimensionlessFraction) -> DimensionlessFraction {
DimensionlessFraction::from(self) - rhs
}
}
impl From<DimensionlessFraction> for f32 {
fn from(was: DimensionlessFraction) -> Self {
was.as_f32()
}
}
impl From<DimensionlessFraction> for f64 {
fn from(was: DimensionlessFraction) -> Self {
was.as_f64()
}
}
impl From<DimensionlessFraction> for Dimensionless<f32> {
fn from(was: DimensionlessFraction) -> Self {
was.as_quantity_f32()
}
}
impl From<DimensionlessFraction> for Dimensionless<f64> {
fn from(was: DimensionlessFraction) -> Self {
was.as_quantity_f64()
}
}
#[macro_export]
macro_rules! mul {
($a: ty, $b: ty) => {
<$a as Mul<$b>>::Output
};
}
pub use mul;
#[macro_export]
macro_rules! div {
($a: ty, $b: ty) => {
<$a as Div<$b>>::Output
};
}
pub use div;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Quantity<T, MM: Integer, S: Integer>(PhantomData<MM>, PhantomData<S>, pub(crate) T);
impl<T, MM: Integer, S: Integer> Quantity<T, MM, S> {
#[inline]
pub const fn new(inner: T) -> Self {
Self(PhantomData, PhantomData, inner)
}
#[inline]
pub fn into_inner(self) -> T {
self.2
}
}
macro_rules! impl_quantity_abs {
($t: ty) => {
impl<MM: Integer, S: Integer> Quantity<$t, MM, S> {
pub const fn abs(self) -> Self {
Self(PhantomData, PhantomData, self.2.abs())
}
}
};
}
impl_quantity_abs!(f32);
impl_quantity_abs!(f64);
impl_quantity_abs!(i8);
impl_quantity_abs!(i16);
impl_quantity_abs!(i32);
impl_quantity_abs!(i64);
impl_quantity_abs!(i128);
impl_quantity_abs!(isize);
impl<T, MM: Integer, S: Integer> From<T> for Quantity<T, MM, S> {
fn from(was: T) -> Self {
Self(PhantomData, PhantomData, was)
}
}
macro_rules! impl_const_ops {
($t: ty) => {
impl<MM: Integer, S: Integer> Quantity<$t, MM, S> {
#[inline]
pub const fn add_const(self, rhs: Self) -> Self {
Quantity::new(self.2 + rhs.2)
}
#[inline]
pub const fn sub_const(self, rhs: Self) -> Self {
Quantity::new(self.2 - rhs.2)
}
}
};
}
impl_const_ops!(f32);
impl_const_ops!(f64);
impl_const_ops!(u8);
impl_const_ops!(u16);
impl_const_ops!(u32);
impl_const_ops!(u64);
impl_const_ops!(u128);
impl_const_ops!(usize);
impl_const_ops!(i8);
impl_const_ops!(i16);
impl_const_ops!(i32);
impl_const_ops!(i64);
impl_const_ops!(i128);
impl_const_ops!(isize);
impl<T: Neg<Output = O>, O, MM: Integer, S: Integer> Neg for Quantity<T, MM, S> {
type Output = Quantity<O, MM, S>;
fn neg(self) -> Quantity<O, MM, S> {
Quantity::new(-self.2)
}
}
impl<T: Add<U, Output = O>, U, O, MM: Integer, S: Integer> Add<Quantity<U, MM, S>>
for Quantity<T, MM, S>
{
type Output = Quantity<O, MM, S>;
fn add(self, rhs: Quantity<U, MM, S>) -> Quantity<O, MM, S> {
Quantity::from(self.2 + rhs.2)
}
}
impl<T: AddAssign<U>, U, MM: Integer, S: Integer> AddAssign<Quantity<U, MM, S>>
for Quantity<T, MM, S>
{
fn add_assign(&mut self, rhs: Quantity<U, MM, S>) {
self.2 += rhs.2;
}
}
impl<T: Sub<U, Output = O>, U, O, MM: Integer, S: Integer> Sub<Quantity<U, MM, S>>
for Quantity<T, MM, S>
{
type Output = Quantity<O, MM, S>;
fn sub(self, rhs: Quantity<U, MM, S>) -> Quantity<O, MM, S> {
Quantity::from(self.2 - rhs.2)
}
}
impl<T: SubAssign<U>, U, MM: Integer, S: Integer> SubAssign<Quantity<U, MM, S>>
for Quantity<T, MM, S>
{
fn sub_assign(&mut self, rhs: Quantity<U, MM, S>) {
self.2 -= rhs.2;
}
}
impl<T: Mul<U, Output = O>, U, O, MM1: Integer, S1: Integer, MM2: Integer, S2: Integer>
Mul<Quantity<U, MM2, S2>> for Quantity<T, MM1, S1>
{
type Output = Quantity<O, MM1::Plus<MM2>, S1::Plus<S2>>;
fn mul(self, rhs: Quantity<U, MM2, S2>) -> Quantity<O, MM1::Plus<MM2>, S1::Plus<S2>> {
Quantity::from(self.2 * rhs.2)
}
}
impl<T: MulAssign<U>, U, MM: Integer, S: Integer> MulAssign<Dimensionless<U>>
for Quantity<T, MM, S>
{
fn mul_assign(&mut self, rhs: Dimensionless<U>) {
self.2 *= rhs.2;
}
}
impl<T: Div<U, Output = O>, U, O, MM1: Integer, S1: Integer, MM2: Integer, S2: Integer>
Div<Quantity<U, MM2, S2>> for Quantity<T, MM1, S1>
{
type Output = Quantity<O, MM1::Minus<MM2>, S1::Minus<S2>>;
fn div(self, rhs: Quantity<U, MM2, S2>) -> Quantity<O, MM1::Minus<MM2>, S1::Minus<S2>> {
Quantity::from(self.2 / rhs.2)
}
}
impl<T: DivAssign<U>, U, MM: Integer, S: Integer> DivAssign<Dimensionless<U>>
for Quantity<T, MM, S>
{
fn div_assign(&mut self, rhs: Dimensionless<U>) {
self.2 /= rhs.2;
}
}
impl<MM: Integer, S: Integer> Mul<Time> for Quantity<f32, MM, S>
where
MM: Integer<Plus<Zero> = MM>,
{
type Output = Quantity<f32, MM, S::Plus<OnePlus<Zero>>>;
fn mul(self, rhs: Time) -> Quantity<f32, MM, S::Plus<OnePlus<Zero>>> {
self * rhs.as_seconds()
}
}
impl<MM: Integer, S: Integer> Mul<Quantity<f32, MM, S>> for Time {
type Output = Quantity<f32, MM, S::PlusOne>;
fn mul(self, rhs: Quantity<f32, MM, S>) -> Quantity<f32, MM, S::PlusOne> {
self.as_seconds() * rhs
}
}
impl<MM: Integer, S: Integer> Div<Time> for Quantity<f32, MM, S>
where
MM: Integer<Minus<Zero> = MM>,
{
type Output = Quantity<f32, MM, S::Minus<OnePlus<Zero>>>;
fn div(self, rhs: Time) -> Quantity<f32, MM, S::Minus<OnePlus<Zero>>> {
self / rhs.as_seconds()
}
}
impl<MM: Integer, S: Integer> Div<Quantity<f32, MM, S>> for Time
where
MM: Integer<Negative = MM>,
{
type Output = Quantity<f32, MM, <<S as Integer>::Negative as Integer>::PlusOne>;
fn div(
self,
rhs: Quantity<f32, MM, S>,
) -> Quantity<f32, MM, <<S as Integer>::Negative as Integer>::PlusOne> {
self.as_seconds() / rhs
}
}
impl<T: fmt::Display, MM: Integer, S: Integer> fmt::Display for Quantity<T, MM, S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} mm^{}s^{}", self.2, MM::as_i8(), S::as_i8())
}
}
impl<T: stulta::Half, MM: Integer, S: Integer> stulta::Half for Quantity<T, MM, S> {
fn half(self) -> Self {
Self::new(self.2.half())
}
}
impl<T: stulta::AbsoluteValue, MM: Integer, S: Integer> stulta::AbsoluteValue
for Quantity<T, MM, S>
{
fn rrtk_abs(self) -> Self {
Self::new(self.2.rrtk_abs())
}
}