kcl_lib/std/
units.rs

1//! Functions related to unitsematics.
2
3use anyhow::Result;
4use kcl_derive_docs::stdlib;
5
6use crate::{
7    errors::KclError,
8    execution::{ExecState, KclValue, UnitLen},
9    std::Args,
10};
11
12/// Millimeters conversion factor for current projects units.
13pub async fn mm(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
14    let result = inner_mm(exec_state)?;
15
16    Ok(args.make_user_val_from_f64(result))
17}
18
19/// Millimeters conversion factor for current projects units.
20///
21/// No matter what units the current project uses, this function will always return the conversion
22/// factor to millimeters.
23///
24/// For example, if the current project uses inches, this function will return `(1/25.4)`.
25/// If the current project uses millimeters, this function will return `1`.
26///
27/// **Caution**: This function is only intended to be used when you absolutely MUST
28/// have different units in your code than the project settings. Otherwise, it is
29/// a bad pattern to use this function.
30///
31/// We merely provide these functions for convenience and readability, as
32/// `10 * mm()` is more readable that your intent is "I want 10 millimeters" than
33/// `10 * (1/25.4)`, if the project settings are in inches.
34///
35/// ```no_run
36/// totalWidth = 10 * mm()
37/// ```
38#[stdlib {
39    name = "mm",
40    tags = ["units"],
41}]
42fn inner_mm(exec_state: &ExecState) -> Result<f64, KclError> {
43    match exec_state.length_unit() {
44        UnitLen::Mm => Ok(1.0),
45        UnitLen::Inches => Ok(measurements::Length::from_millimeters(1.0).as_inches()),
46        UnitLen::Feet => Ok(measurements::Length::from_millimeters(1.0).as_feet()),
47        UnitLen::M => Ok(measurements::Length::from_millimeters(1.0).as_meters()),
48        UnitLen::Cm => Ok(measurements::Length::from_millimeters(1.0).as_centimeters()),
49        UnitLen::Yards => Ok(measurements::Length::from_millimeters(1.0).as_yards()),
50    }
51}
52
53/// Inches conversion factor for current projects units.
54pub async fn inch(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
55    let result = inner_inch(exec_state)?;
56
57    Ok(args.make_user_val_from_f64(result))
58}
59
60/// Inches conversion factor for current projects units.
61///
62/// No matter what units the current project uses, this function will always return the conversion
63/// factor to inches.
64///
65/// For example, if the current project uses inches, this function will return `1`.
66/// If the current project uses millimeters, this function will return `25.4`.
67///
68/// **Caution**: This function is only intended to be used when you absolutely MUST
69/// have different units in your code than the project settings. Otherwise, it is
70/// a bad pattern to use this function.
71///
72/// We merely provide these functions for convenience and readability, as
73/// `10 * inch()` is more readable that your intent is "I want 10 inches" than
74/// `10 * 25.4`, if the project settings are in millimeters.
75///
76/// ```no_run
77/// totalWidth = 10 * inch()
78/// ```
79#[stdlib {
80    name = "inch",
81    tags = ["units"],
82}]
83fn inner_inch(exec_state: &ExecState) -> Result<f64, KclError> {
84    match exec_state.length_unit() {
85        UnitLen::Mm => Ok(measurements::Length::from_inches(1.0).as_millimeters()),
86        UnitLen::Inches => Ok(1.0),
87        UnitLen::Feet => Ok(measurements::Length::from_inches(1.0).as_feet()),
88        UnitLen::M => Ok(measurements::Length::from_inches(1.0).as_meters()),
89        UnitLen::Cm => Ok(measurements::Length::from_inches(1.0).as_centimeters()),
90        UnitLen::Yards => Ok(measurements::Length::from_inches(1.0).as_yards()),
91    }
92}
93
94/// Feet conversion factor for current projects units.
95pub async fn ft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
96    let result = inner_ft(exec_state)?;
97
98    Ok(args.make_user_val_from_f64(result))
99}
100
101/// Feet conversion factor for current projects units.
102///
103/// No matter what units the current project uses, this function will always return the conversion
104/// factor to feet.
105///
106/// For example, if the current project uses inches, this function will return `12`.
107/// If the current project uses millimeters, this function will return `304.8`.
108/// If the current project uses feet, this function will return `1`.
109///
110/// **Caution**: This function is only intended to be used when you absolutely MUST
111/// have different units in your code than the project settings. Otherwise, it is
112/// a bad pattern to use this function.
113///
114/// We merely provide these functions for convenience and readability, as
115/// `10 * ft()` is more readable that your intent is "I want 10 feet" than
116/// `10 * 304.8`, if the project settings are in millimeters.
117///
118/// ```no_run
119/// totalWidth = 10 * ft()
120/// ```
121#[stdlib {
122    name = "ft",
123    tags = ["units"],
124}]
125fn inner_ft(exec_state: &ExecState) -> Result<f64, KclError> {
126    match exec_state.length_unit() {
127        UnitLen::Mm => Ok(measurements::Length::from_feet(1.0).as_millimeters()),
128        UnitLen::Inches => Ok(measurements::Length::from_feet(1.0).as_inches()),
129        UnitLen::Feet => Ok(1.0),
130        UnitLen::M => Ok(measurements::Length::from_feet(1.0).as_meters()),
131        UnitLen::Cm => Ok(measurements::Length::from_feet(1.0).as_centimeters()),
132        UnitLen::Yards => Ok(measurements::Length::from_feet(1.0).as_yards()),
133    }
134}
135
136/// Meters conversion factor for current projects units.
137pub async fn m(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
138    let result = inner_m(exec_state)?;
139
140    Ok(args.make_user_val_from_f64(result))
141}
142
143/// Meters conversion factor for current projects units.
144///
145/// No matter what units the current project uses, this function will always return the conversion
146/// factor to meters.
147///
148/// For example, if the current project uses inches, this function will return `39.3701`.
149/// If the current project uses millimeters, this function will return `1000`.
150/// If the current project uses meters, this function will return `1`.
151///
152/// **Caution**: This function is only intended to be used when you absolutely MUST
153/// have different units in your code than the project settings. Otherwise, it is
154/// a bad pattern to use this function.
155///
156/// We merely provide these functions for convenience and readability, as
157/// `10 * m()` is more readable that your intent is "I want 10 meters" than
158/// `10 * 1000`, if the project settings are in millimeters.
159///
160/// ```no_run
161/// totalWidth = 10 * m()
162/// ```
163#[stdlib {
164    name = "m",
165    tags = ["units"],
166}]
167fn inner_m(exec_state: &ExecState) -> Result<f64, KclError> {
168    match exec_state.length_unit() {
169        UnitLen::Mm => Ok(measurements::Length::from_meters(1.0).as_millimeters()),
170        UnitLen::Inches => Ok(measurements::Length::from_meters(1.0).as_inches()),
171        UnitLen::Feet => Ok(measurements::Length::from_meters(1.0).as_feet()),
172        UnitLen::M => Ok(1.0),
173        UnitLen::Cm => Ok(measurements::Length::from_meters(1.0).as_centimeters()),
174        UnitLen::Yards => Ok(measurements::Length::from_meters(1.0).as_yards()),
175    }
176}
177
178/// Centimeters conversion factor for current projects units.
179pub async fn cm(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
180    let result = inner_cm(exec_state)?;
181
182    Ok(args.make_user_val_from_f64(result))
183}
184
185/// Centimeters conversion factor for current projects units.
186///
187/// No matter what units the current project uses, this function will always return the conversion
188/// factor to centimeters.
189///
190/// For example, if the current project uses inches, this function will return `0.393701`.
191/// If the current project uses millimeters, this function will return `10`.
192/// If the current project uses centimeters, this function will return `1`.
193///
194/// **Caution**: This function is only intended to be used when you absolutely MUST
195/// have different units in your code than the project settings. Otherwise, it is
196/// a bad pattern to use this function.
197///
198/// We merely provide these functions for convenience and readability, as
199/// `10 * cm()` is more readable that your intent is "I want 10 centimeters" than
200/// `10 * 10`, if the project settings are in millimeters.
201///
202/// ```no_run
203/// totalWidth = 10 * cm()
204/// ```
205#[stdlib {
206    name = "cm",
207    tags = ["units"],
208}]
209fn inner_cm(exec_state: &ExecState) -> Result<f64, KclError> {
210    match exec_state.length_unit() {
211        UnitLen::Mm => Ok(measurements::Length::from_centimeters(1.0).as_millimeters()),
212        UnitLen::Inches => Ok(measurements::Length::from_centimeters(1.0).as_inches()),
213        UnitLen::Feet => Ok(measurements::Length::from_centimeters(1.0).as_feet()),
214        UnitLen::M => Ok(measurements::Length::from_centimeters(1.0).as_meters()),
215        UnitLen::Cm => Ok(1.0),
216        UnitLen::Yards => Ok(measurements::Length::from_centimeters(1.0).as_yards()),
217    }
218}
219
220/// Yards conversion factor for current projects units.
221pub async fn yd(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
222    let result = inner_yd(exec_state)?;
223
224    Ok(args.make_user_val_from_f64(result))
225}
226
227/// Yards conversion factor for current projects units.
228///
229/// No matter what units the current project uses, this function will always return the conversion
230/// factor to yards.
231///
232/// For example, if the current project uses inches, this function will return `36`.
233/// If the current project uses millimeters, this function will return `914.4`.
234/// If the current project uses yards, this function will return `1`.
235///
236/// **Caution**: This function is only intended to be used when you absolutely MUST
237/// have different units in your code than the project settings. Otherwise, it is
238/// a bad pattern to use this function.
239///
240/// We merely provide these functions for convenience and readability, as
241/// `10 * yd()` is more readable that your intent is "I want 10 yards" than
242/// `10 * 914.4`, if the project settings are in millimeters.
243///
244/// ```no_run
245/// totalWidth = 10 * yd()
246/// ```
247#[stdlib {
248    name = "yd",
249    tags = ["units"],
250}]
251fn inner_yd(exec_state: &ExecState) -> Result<f64, KclError> {
252    match exec_state.length_unit() {
253        UnitLen::Mm => Ok(measurements::Length::from_yards(1.0).as_millimeters()),
254        UnitLen::Inches => Ok(measurements::Length::from_yards(1.0).as_inches()),
255        UnitLen::Feet => Ok(measurements::Length::from_yards(1.0).as_feet()),
256        UnitLen::M => Ok(measurements::Length::from_yards(1.0).as_meters()),
257        UnitLen::Cm => Ok(measurements::Length::from_yards(1.0).as_centimeters()),
258        UnitLen::Yards => Ok(1.0),
259    }
260}