diman_unit_system 0.4.0

Internal procedural macros for diman.
Documentation
use std::collections::HashMap;

use proc_macro2::Ident;

use crate::{expression::MulDiv, types::BaseDimensionExponent};

#[derive(Clone)]
pub struct BaseDimensions {
    pub fields: HashMap<Ident, BaseDimensionExponent>,
}

impl PartialEq for BaseDimensions {
    fn eq(&self, other: &Self) -> bool {
        self.fields.iter().all(|(dimension, value)| {
            if let Some(corresponding_value) = other.fields.get(dimension) {
                value == corresponding_value
            } else {
                false
            }
        })
    }
}
impl BaseDimensions {
    pub fn none() -> Self {
        Self {
            fields: HashMap::default(),
        }
    }
}

impl std::ops::Mul for BaseDimensions {
    type Output = Self;

    #[allow(clippy::suspicious_arithmetic_impl)]
    fn mul(self, rhs: Self) -> Self::Output {
        let mut fields = self.fields;
        for (name_rhs, val_rhs) in rhs.fields {
            let same_field = fields.get_mut(&name_rhs);
            if let Some(val) = same_field {
                *val += val_rhs;
            } else {
                fields.insert(name_rhs, val_rhs);
            }
        }
        Self { fields }
    }
}

impl BaseDimensions {
    fn inv(mut self) -> Self {
        for (_, value) in self.fields.iter_mut() {
            *value = -*value;
        }
        self
    }
}

impl std::ops::Div for BaseDimensions {
    type Output = Self;

    #[allow(clippy::suspicious_arithmetic_impl)]
    fn div(self, rhs: Self) -> Self::Output {
        self * rhs.inv()
    }
}

impl MulDiv for BaseDimensions {
    fn pow(self, pow: BaseDimensionExponent) -> Self {
        BaseDimensions {
            fields: self
                .fields
                .into_iter()
                .map(|(ident, value)| (ident, value * pow))
                .collect(),
        }
    }
}

#[derive(Clone)]
pub struct DimensionsAndFactor {
    pub dimensions: BaseDimensions,
    pub factor: f64,
}

impl DimensionsAndFactor {
    pub fn factor(factor: f64) -> Self {
        Self {
            dimensions: BaseDimensions::none(),
            factor,
        }
    }

    pub(crate) fn dimensions(dimensions: BaseDimensions) -> Self {
        Self {
            dimensions,
            factor: 1.0,
        }
    }
}

impl std::ops::Mul for DimensionsAndFactor {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self::Output {
        Self {
            dimensions: self.dimensions * rhs.dimensions,
            factor: self.factor * rhs.factor,
        }
    }
}

impl std::ops::Div for DimensionsAndFactor {
    type Output = Self;

    fn div(self, rhs: Self) -> Self::Output {
        Self {
            dimensions: self.dimensions / rhs.dimensions,
            factor: self.factor / rhs.factor,
        }
    }
}

impl MulDiv for DimensionsAndFactor {
    fn pow(self, pow: BaseDimensionExponent) -> Self {
        Self {
            factor: BaseDimensionExponent::pow(self.factor, pow),
            dimensions: self.dimensions.pow(pow),
        }
    }
}