Skip to main content

microcad_lang/value/quantity/
mod.rs

1// Copyright © 2025-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Matrix value type
5
6pub mod error;
7pub mod ops;
8
9use crate::ty::*;
10use microcad_core::*;
11
12pub use error::*;
13
14const OUTPUT_PRECISION: i32 = 14;
15
16/// A numeric value
17#[derive(Clone, Debug)]
18pub struct Quantity {
19    /// The numeric value of the quantity.
20    pub value: Scalar,
21    /// The quantity type with a base unit.
22    pub quantity_type: QuantityType,
23    /// The original unit of the quantity,
24    pub unit: Unit,
25}
26
27impl PartialEq for Quantity {
28    fn eq(&self, other: &Self) -> bool {
29        // 1. Ensure the types match first
30        if self.quantity_type != other.quantity_type {
31            return false;
32        }
33
34        // 2. Compare values within the allowed precision
35        let epsilon = 10.0_f64.powi(-OUTPUT_PRECISION);
36        (self.value - other.value).abs() < epsilon
37    }
38}
39
40impl Quantity {
41    /// Create a new quantity.
42    pub fn new(value: Scalar, quantity_type: QuantityType) -> Self {
43        Self {
44            value,
45            unit: quantity_type.base_unit(),
46            quantity_type,
47        }
48    }
49    /// Transforms the internal value using a closure.
50    pub fn map<F>(self, f: F) -> Self
51    where
52        F: FnOnce(Scalar) -> Scalar,
53    {
54        Self {
55            value: f(self.value),
56            quantity_type: self.quantity_type,
57            unit: self.unit,
58        }
59    }
60
61    /// Create a new Scalar quantity.
62    pub fn scalar(value: Scalar) -> Self {
63        Quantity::new(value, QuantityType::Scalar)
64    }
65
66    /// Create a new Length quantity in millimeters.
67    pub fn length(length: Scalar) -> Self {
68        Quantity::new(length, QuantityType::Length)
69    }
70
71    /// Calculate the power of quantity.
72    ///
73    /// *Note: This function has not been implemented completely.*
74    pub fn pow(&self, rhs: &Quantity) -> Self {
75        match (&self.quantity_type, &rhs.quantity_type) {
76            (QuantityType::Scalar, QuantityType::Scalar) => {
77                Quantity::new(self.value.powf(rhs.value), QuantityType::Scalar)
78            }
79            _ => todo!(),
80        }
81    }
82
83    /// Calculate the power of quantity and an integer.
84    ///
85    /// *Note: This function has not been implemented completely.*
86    pub fn pow_int(&self, rhs: &Integer) -> Self {
87        match &self.quantity_type {
88            QuantityType::Scalar => {
89                Quantity::new(self.value.powi(*rhs as i32), QuantityType::Scalar)
90            }
91            QuantityType::Length => todo!(),
92            QuantityType::Area => todo!(),
93            QuantityType::Volume => todo!(),
94            QuantityType::Density => todo!(),
95            QuantityType::Angle => todo!(),
96            QuantityType::Weight => todo!(),
97            QuantityType::Invalid => todo!(),
98        }
99    }
100}
101
102impl PartialOrd for Quantity {
103    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
104        if self.quantity_type == other.quantity_type {
105            self.value.partial_cmp(&other.value)
106        } else {
107            None
108        }
109    }
110}
111
112impl From<Scalar> for Quantity {
113    fn from(value: Scalar) -> Self {
114        Self::new(value, QuantityType::Scalar)
115    }
116}
117
118impl From<Integer> for Quantity {
119    fn from(value: Integer) -> Self {
120        Self::new(value as Scalar, QuantityType::Scalar)
121    }
122}
123
124impl From<Length> for Quantity {
125    fn from(length: Length) -> Self {
126        Self::new(*length, QuantityType::Length)
127    }
128}
129
130impl Ty for Quantity {
131    fn ty(&self) -> Type {
132        Type::Quantity(self.quantity_type.clone())
133    }
134}
135
136impl std::fmt::Display for Quantity {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        write!(
139            f,
140            "{}{}",
141            round::round(self.unit.denormalize(self.value), OUTPUT_PRECISION),
142            self.unit
143        )
144    }
145}
146
147impl std::hash::Hash for Quantity {
148    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
149        bytemuck::bytes_of(&self.value).hash(state);
150        self.quantity_type.hash(state)
151    }
152}