Skip to main content

kittycad_modeling_cmds/
units.rs

1use kittycad_unit_conversion_derive::UnitConversion;
2use parse_display_derive::{Display, FromStr};
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "cxx")]
7use crate::impl_extern_type;
8
9/// The valid types of length units.
10#[derive(
11    Default,
12    Display,
13    FromStr,
14    Copy,
15    Eq,
16    PartialEq,
17    Debug,
18    JsonSchema,
19    Deserialize,
20    Serialize,
21    Clone,
22    Ord,
23    PartialOrd,
24    UnitConversion,
25    Hash,
26)]
27#[cfg_attr(feature = "tabled", derive(tabled::Tabled))]
28#[display(style = "snake_case")]
29#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
30#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
31#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
32#[cfg_attr(
33    feature = "python",
34    pyo3::pyclass(eq, from_py_object),
35    pyo3_stub_gen::derive::gen_stub_pyclass_enum
36)]
37pub enum UnitLength {
38    /// Centimeters <https://en.wikipedia.org/wiki/Centimeter>
39    #[serde(rename = "cm")]
40    #[display("cm")]
41    Centimeters,
42    /// Feet <https://en.wikipedia.org/wiki/Foot_(unit)>
43    #[serde(rename = "ft")]
44    #[display("ft")]
45    Feet,
46    /// Inches <https://en.wikipedia.org/wiki/Inch>
47    #[serde(rename = "in")]
48    #[display("in")]
49    Inches,
50    /// Meters <https://en.wikipedia.org/wiki/Meter>
51    #[default]
52    #[serde(rename = "m")]
53    #[display("m")]
54    Meters,
55    /// Millimeters <https://en.wikipedia.org/wiki/Millimeter>
56    #[serde(rename = "mm")]
57    #[display("mm")]
58    Millimeters,
59    /// Yards <https://en.wikipedia.org/wiki/Yard>
60    #[serde(rename = "yd")]
61    #[display("yd")]
62    Yards,
63}
64
65impl UnitLength {
66    /// Convert to measurement.
67    pub fn as_measurement(self, value: f64) -> measurements::Length {
68        match self {
69            Self::Centimeters => measurements::Length::from_centimeters(value),
70            Self::Feet => measurements::Length::from_feet(value),
71            Self::Inches => measurements::Length::from_inches(value),
72            Self::Meters => measurements::Length::from_meters(value),
73            Self::Millimeters => measurements::Length::from_millimeters(value),
74            Self::Yards => measurements::Length::from_yards(value),
75        }
76    }
77}
78
79#[cfg(feature = "cxx")]
80impl_extern_type! {
81    [Trivial]
82    UnitLength = "Enums::_UnitLength"
83}
84
85/// The valid types of angle formats.
86#[derive(
87    Default,
88    Display,
89    FromStr,
90    Copy,
91    Eq,
92    PartialEq,
93    Debug,
94    JsonSchema,
95    Deserialize,
96    Serialize,
97    Clone,
98    Ord,
99    PartialOrd,
100    UnitConversion,
101    Hash,
102)]
103#[cfg_attr(feature = "tabled", derive(tabled::Tabled))]
104#[serde(rename_all = "snake_case")]
105#[display(style = "snake_case")]
106#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
107#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
108#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
109#[cfg_attr(
110    feature = "python",
111    pyo3::pyclass(eq, from_py_object),
112    pyo3_stub_gen::derive::gen_stub_pyclass_enum
113)]
114pub enum UnitAngle {
115    /// Degrees <https://en.wikipedia.org/wiki/Degree_(angle)>
116    #[default]
117    #[display("deg")]
118    Degrees,
119    /// Radians <https://en.wikipedia.org/wiki/Radian>
120    #[display("rad")]
121    Radians,
122}
123
124/// The valid types of area units.
125#[derive(
126    Display,
127    FromStr,
128    Copy,
129    Eq,
130    PartialEq,
131    Debug,
132    JsonSchema,
133    Deserialize,
134    Serialize,
135    Clone,
136    Ord,
137    PartialOrd,
138    UnitConversion,
139    Default,
140    Hash,
141)]
142#[cfg_attr(feature = "tabled", derive(tabled::Tabled))]
143#[serde(rename_all = "snake_case")]
144#[display(style = "snake_case")]
145#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
146#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
147#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
148#[cfg_attr(
149    feature = "python",
150    pyo3::pyclass(eq, from_py_object),
151    pyo3_stub_gen::derive::gen_stub_pyclass_enum
152)]
153pub enum UnitArea {
154    /// Square centimeters <https://en.wikipedia.org/wiki/Square_centimeter>
155    #[serde(rename = "cm2")]
156    #[display("cm2")]
157    SquareCentimeters,
158    /// Square decimeters <https://en.wikipedia.org/wiki/Square_decimeter>
159    #[serde(rename = "dm2")]
160    #[display("dm2")]
161    SquareDecimeters,
162    /// Square feet <https://en.wikipedia.org/wiki/Square_foot>
163    #[serde(rename = "ft2")]
164    #[display("ft2")]
165    SquareFeet,
166    /// Square inches <https://en.wikipedia.org/wiki/Square_inch>
167    #[serde(rename = "in2")]
168    #[display("in2")]
169    SquareInches,
170    /// Square kilometers <https://en.wikipedia.org/wiki/Square_kilometer>
171    #[serde(rename = "km2")]
172    #[display("km2")]
173    SquareKilometers,
174    /// Square meters <https://en.wikipedia.org/wiki/Square_meter>
175    #[default]
176    #[serde(rename = "m2")]
177    #[display("m2")]
178    SquareMeters,
179    /// Square millimeters <https://en.wikipedia.org/wiki/Square_millimeter>
180    #[serde(rename = "mm2")]
181    #[display("mm2")]
182    SquareMillimeters,
183    /// Square yards <https://en.wikipedia.org/wiki/Square_mile>
184    #[serde(rename = "yd2")]
185    #[display("yd2")]
186    SquareYards,
187}
188
189impl UnitArea {
190    /// Convert to measurement.
191    pub fn as_measurement(self, value: f64) -> measurements::Area {
192        match self {
193            Self::SquareCentimeters => measurements::Area::from_square_centimeters(value),
194            Self::SquareDecimeters => measurements::Area::from_square_decimeters(value),
195            Self::SquareFeet => measurements::Area::from_square_feet(value),
196            Self::SquareInches => measurements::Area::from_square_inches(value),
197            Self::SquareKilometers => measurements::Area::from_square_kilometers(value),
198            Self::SquareMeters => measurements::Area::from_square_meters(value),
199            Self::SquareMillimeters => measurements::Area::from_square_millimeters(value),
200            Self::SquareYards => measurements::Area::from_square_yards(value),
201        }
202    }
203}
204
205/// The valid types for density units.
206#[derive(
207    Display,
208    Copy,
209    Eq,
210    PartialEq,
211    Debug,
212    JsonSchema,
213    Deserialize,
214    Serialize,
215    Clone,
216    Ord,
217    PartialOrd,
218    Default,
219    UnitConversion,
220    Hash,
221)]
222#[cfg_attr(feature = "tabled", derive(tabled::Tabled))]
223#[display(style = "snake_case")]
224#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
225#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
226#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
227#[cfg_attr(
228    feature = "python",
229    pyo3::pyclass(eq, from_py_object),
230    pyo3_stub_gen::derive::gen_stub_pyclass_enum
231)]
232pub enum UnitDensity {
233    /// Pounds per cubic feet.
234    #[serde(rename = "lb:ft3")]
235    #[display("lb:ft3")]
236    PoundsPerCubicFeet,
237
238    /// Kilograms per cubic meter.
239    #[default]
240    #[serde(rename = "kg:m3")]
241    #[display("kg:m3")]
242    KilogramsPerCubicMeter,
243}
244
245impl std::str::FromStr for UnitDensity {
246    type Err = parse_display::ParseError;
247
248    fn from_str(s: &str) -> Result<Self, Self::Err> {
249        match s {
250            "lbft3" | "lb:ft3" | "lb-ft3" => Ok(Self::PoundsPerCubicFeet),
251            "kgm3" | "kg:m3" | "kg-m3" => Ok(Self::KilogramsPerCubicMeter),
252            _other => Err(Default::default()),
253        }
254    }
255}
256
257impl UnitDensity {
258    /// Convert to measurement.
259    pub fn as_measurement(self, value: f64) -> measurements::Density {
260        match self {
261            Self::PoundsPerCubicFeet => measurements::Density::from_pounds_per_cubic_feet(value),
262            Self::KilogramsPerCubicMeter => measurements::Density::from_kilograms_per_cubic_meter(value),
263        }
264    }
265}
266
267/// The valid types of mass units.
268#[derive(
269    Default,
270    Display,
271    FromStr,
272    Copy,
273    Eq,
274    PartialEq,
275    Debug,
276    JsonSchema,
277    Deserialize,
278    Serialize,
279    Clone,
280    Ord,
281    PartialOrd,
282    UnitConversion,
283    Hash,
284)]
285#[cfg_attr(feature = "tabled", derive(tabled::Tabled))]
286#[serde(rename_all = "snake_case")]
287#[display(style = "snake_case")]
288#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
289#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
290#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
291#[cfg_attr(
292    feature = "python",
293    pyo3::pyclass(eq, from_py_object),
294    pyo3_stub_gen::derive::gen_stub_pyclass_enum
295)]
296pub enum UnitMass {
297    /// Grams <https://en.wikipedia.org/wiki/Gram>
298    #[default]
299    #[serde(rename = "g")]
300    #[display("g")]
301    Grams,
302    /// Kilograms <https://en.wikipedia.org/wiki/Kilogram>
303    #[serde(rename = "kg")]
304    #[display("kg")]
305    Kilograms,
306    /// Pounds <https://en.wikipedia.org/wiki/Pound_(mass)>
307    #[serde(rename = "lb")]
308    #[display("lb")]
309    Pounds,
310}
311
312impl UnitMass {
313    /// Convert to measurement.
314    pub fn as_measurement(self, value: f64) -> measurements::Mass {
315        match self {
316            Self::Grams => measurements::Mass::from_grams(value),
317            Self::Kilograms => measurements::Mass::from_kilograms(value),
318            Self::Pounds => measurements::Mass::from_pounds(value),
319        }
320    }
321}
322
323/// The valid types of volume units.
324#[derive(
325    Default,
326    Display,
327    FromStr,
328    Copy,
329    Eq,
330    PartialEq,
331    Debug,
332    JsonSchema,
333    Deserialize,
334    Serialize,
335    Clone,
336    Ord,
337    PartialOrd,
338    UnitConversion,
339    Hash,
340)]
341#[cfg_attr(feature = "tabled", derive(tabled::Tabled))]
342#[display(style = "snake_case")]
343#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
344#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
345#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
346#[cfg_attr(
347    feature = "python",
348    pyo3::pyclass(eq, from_py_object),
349    pyo3_stub_gen::derive::gen_stub_pyclass_enum
350)]
351pub enum UnitVolume {
352    /// Cubic millimeters (mm³)
353    #[serde(rename = "mm3")]
354    #[display("mm3")]
355    CubicMillimeters,
356    /// Cubic centimeters (cc or cm³) <https://en.wikipedia.org/wiki/Cubic_centimeter>
357    #[serde(rename = "cm3")]
358    #[display("cm3")]
359    CubicCentimeters,
360    /// Cubic feet (ft³) <https://en.wikipedia.org/wiki/Cubic_foot>
361    #[serde(rename = "ft3")]
362    #[display("ft3")]
363    CubicFeet,
364    /// Cubic inches (cu in or in³) <https://en.wikipedia.org/wiki/Cubic_inch>
365    #[serde(rename = "in3")]
366    #[display("in3")]
367    CubicInches,
368    /// Cubic meters (m³) <https://en.wikipedia.org/wiki/Cubic_meter>
369    #[default]
370    #[serde(rename = "m3")]
371    #[display("m3")]
372    CubicMeters,
373    /// Cubic yards (yd³) <https://en.wikipedia.org/wiki/Cubic_yard>
374    #[serde(rename = "yd3")]
375    #[display("yd3")]
376    CubicYards,
377    /// US Fluid Ounces (fl oz) <https://en.wikipedia.org/wiki/Fluid_ounce>
378    #[serde(rename = "usfloz")]
379    #[display("usfloz")]
380    FluidOunces,
381    /// US Gallons (gal US) <https://en.wikipedia.org/wiki/Gallon>
382    #[serde(rename = "usgal")]
383    #[display("usgal")]
384    Gallons,
385    /// Liters (l) <https://en.wikipedia.org/wiki/Litre>
386    #[serde(rename = "l")]
387    #[display("l")]
388    Liters,
389    /// Milliliters (ml) <https://en.wikipedia.org/wiki/Litre>
390    #[serde(rename = "ml")]
391    #[display("ml")]
392    Milliliters,
393}
394
395impl UnitVolume {
396    /// Convert to measurement.
397    pub fn as_measurement(self, value: f64) -> measurements::Volume {
398        match self {
399            Self::CubicMillimeters => measurements::Volume::from_cubic_millimeters(value),
400            Self::CubicCentimeters => measurements::Volume::from_cubic_centimeters(value),
401            Self::CubicFeet => measurements::Volume::from_cubic_feet(value),
402            Self::CubicInches => measurements::Volume::from_cubic_inches(value),
403            Self::CubicMeters => measurements::Volume::from_cubic_meters(value),
404            Self::CubicYards => measurements::Volume::from_cubic_yards(value),
405            Self::FluidOunces => measurements::Volume::from_fluid_ounces(value),
406            Self::Gallons => measurements::Volume::from_gallons(value),
407            Self::Liters => measurements::Volume::from_liters(value),
408            Self::Milliliters => measurements::Volume::from_milliliters(value),
409        }
410    }
411}