Skip to main content

kcl_lib/std/
mod.rs

1//! Functions implemented for language execution.
2
3pub mod appearance;
4pub mod args;
5pub mod array;
6pub mod assert;
7pub mod axis_or_reference;
8pub mod chamfer;
9pub mod clone;
10pub mod constraints;
11pub mod csg;
12pub mod edge;
13pub mod extrude;
14pub mod faces;
15pub mod fail;
16pub mod fillet;
17pub mod gdt;
18pub mod helix;
19pub mod ids;
20pub mod loft;
21pub mod math;
22pub mod mirror;
23pub mod patterns;
24pub mod planes;
25pub(crate) mod region_consumption;
26pub mod revolve;
27pub mod runtime;
28pub mod segment;
29pub mod shapes;
30pub mod shell;
31pub mod sketch;
32pub(crate) mod solid_consumption;
33pub(crate) mod solver;
34pub mod string;
35pub mod surfaces;
36pub mod sweep;
37pub mod transform;
38pub mod utils;
39pub mod view;
40
41use anyhow::Result;
42pub use args::Args;
43use futures::future::FutureExt;
44
45use crate::errors::KclError;
46use crate::execution::ConsumedRegionOperation;
47use crate::execution::ExecState;
48use crate::execution::KclValue;
49use crate::execution::KclValueControlFlow;
50use crate::execution::types::PrimitiveType;
51
52pub type StdFn =
53    fn(
54        &mut ExecState,
55        Args,
56    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<KclValueControlFlow, KclError>> + Send + '_>>;
57
58#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
59pub(crate) enum ConsumedSolidArgCheck {
60    #[default]
61    Error,
62    WarnDeprecated,
63}
64
65#[derive(Clone, Copy, Debug, PartialEq, Eq)]
66pub(crate) enum ConsumedRegionDuplicatePolicy {
67    Reject,
68    Deduplicate,
69}
70
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub(crate) enum ConsumedRegionAliasPolicy {
73    None,
74    Reject(&'static str),
75    Preserve(&'static str),
76}
77
78#[derive(Clone, Copy, Debug, PartialEq, Eq)]
79pub(crate) struct ConsumedRegionArg {
80    pub(crate) operation: ConsumedRegionOperation,
81    pub(crate) duplicate_policy: ConsumedRegionDuplicatePolicy,
82    pub(crate) alias_policy: ConsumedRegionAliasPolicy,
83    pub(crate) stale_region_policy: StaleRegionPolicy,
84}
85
86impl ConsumedRegionArg {
87    pub(crate) const fn new(operation: ConsumedRegionOperation) -> Self {
88        Self {
89            operation,
90            duplicate_policy: ConsumedRegionDuplicatePolicy::Reject,
91            alias_policy: ConsumedRegionAliasPolicy::None,
92            stale_region_policy: StaleRegionPolicy::Error,
93        }
94    }
95
96    pub(crate) const fn reject_alias_with(mut self, arg_name: &'static str) -> Self {
97        self.alias_policy = ConsumedRegionAliasPolicy::Reject(arg_name);
98        self
99    }
100
101    pub(crate) const fn preserve_alias_with(mut self, arg_name: &'static str) -> Self {
102        self.alias_policy = ConsumedRegionAliasPolicy::Preserve(arg_name);
103        self
104    }
105
106    pub(crate) const fn deduplicate(mut self) -> Self {
107        self.duplicate_policy = ConsumedRegionDuplicatePolicy::Deduplicate;
108        self
109    }
110
111    pub(crate) const fn warn_if_already_consumed(mut self) -> Self {
112        self.stale_region_policy = StaleRegionPolicy::Warning;
113        self
114    }
115}
116
117#[derive(Clone, Copy, Debug, PartialEq, Eq)]
118pub(crate) enum StaleRegionPolicy {
119    Error,
120    Warning,
121}
122
123#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
124pub(crate) enum RegionBehavior {
125    /// Warn when a consumed region reaches a Rust-backed stdlib function.
126    #[default]
127    WarnOnConsumed,
128    /// Apply the configured stale-region policy and record the specified inputs
129    /// as consumed after success.
130    Consume(ConsumedRegionArg),
131    /// The function reads stored region data without sending its object ID to the engine.
132    ReadLocal,
133}
134
135impl RegionBehavior {
136    pub(crate) const fn stale_region_policy(self) -> Option<StaleRegionPolicy> {
137        match self {
138            Self::WarnOnConsumed => Some(StaleRegionPolicy::Warning),
139            Self::Consume(policy) => Some(policy.stale_region_policy),
140            Self::ReadLocal => None,
141        }
142    }
143}
144
145#[derive(Clone, Debug, PartialEq, Eq)]
146pub struct StdFnProps {
147    pub name: String,
148    pub(crate) consumed_solid_arg_check: ConsumedSolidArgCheck,
149    pub(crate) region_behavior: RegionBehavior,
150}
151
152impl StdFnProps {
153    pub(crate) fn default(name: &str) -> Self {
154        Self {
155            name: name.to_owned(),
156            consumed_solid_arg_check: Default::default(),
157            region_behavior: Default::default(),
158        }
159    }
160
161    pub(crate) fn warn_deprecated_on_consumed_solid_args(mut self) -> Self {
162        self.consumed_solid_arg_check = ConsumedSolidArgCheck::WarnDeprecated;
163        self
164    }
165
166    pub(crate) fn consumes_regions(mut self, consumed_region_arg: ConsumedRegionArg) -> Self {
167        self.region_behavior = RegionBehavior::Consume(consumed_region_arg);
168        self
169    }
170
171    pub(crate) fn reads_regions_locally(mut self) -> Self {
172        self.region_behavior = RegionBehavior::ReadLocal;
173        self
174    }
175}
176
177/// Resolves a Rust-backed standard-library function and its execution policies.
178///
179/// When registering a new function, start with `StdFnProps::default(...)`. Its
180/// fully qualified name is used in diagnostics. Then add modifiers according to
181/// how the function handles values consumed by earlier engine operations:
182///
183/// - Keep the default region behavior if the function does not accept Regions,
184///   or may use a Region's engine UUID without consuming it. A stale Region
185///   produces a warning and the call continues.
186/// - Use [`StdFnProps::reads_regions_locally`] only when the function itself
187///   uses stored KCL data and never sends an input Region's UUID to the engine.
188///   Calls made by callbacks or KCL wrappers apply their own policies.
189/// - Use [`StdFnProps::consumes_regions`] when a successful call consumes Regions
190///   in its unlabeled input. By default, the function rejects stale Regions,
191///   rejects duplicate Regions in that input, and records the Regions as consumed
192///   after success. The modifiers define engine-specific exceptions:
193///   - [`ConsumedRegionArg::warn_if_already_consumed`] warns instead of rejecting
194///     stale Regions.
195///   - [`ConsumedRegionArg::deduplicate`] allows duplicate Regions in the input.
196///   - [`ConsumedRegionArg::reject_alias_with`] rejects a Region that is also
197///     passed in the named argument.
198///   - [`ConsumedRegionArg::preserve_alias_with`] does not record a Region as
199///     consumed when it is also passed in the named argument.
200/// - Keep the default consumed-solid behavior for new functions. Use
201///   [`StdFnProps::warn_deprecated_on_consumed_solid_args`] only as a temporary
202///   compatibility exception that warns instead of rejecting the call.
203///
204/// Region and solid policies are independent, so their modifiers may be chained.
205pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProps) {
206    match (path, fn_name) {
207        ("gdt", "datum") => (
208            |e, a| Box::pin(crate::std::gdt::datum(e, a).map(|r| r.map(KclValue::continue_))),
209            StdFnProps::default("std::gdt::datum"),
210        ),
211        ("gdt", "flatness") => (
212            |e, a| Box::pin(crate::std::gdt::flatness(e, a).map(|r| r.map(KclValue::continue_))),
213            StdFnProps::default("std::gdt::flatness"),
214        ),
215        ("gdt", "straightness") => (
216            |e, a| Box::pin(crate::std::gdt::straightness(e, a).map(|r| r.map(KclValue::continue_))),
217            StdFnProps::default("std::gdt::straightness"),
218        ),
219        ("gdt", "circularity") => (
220            |e, a| Box::pin(crate::std::gdt::circularity(e, a).map(|r| r.map(KclValue::continue_))),
221            StdFnProps::default("std::gdt::circularity"),
222        ),
223        ("gdt", "cylindricity") => (
224            |e, a| Box::pin(crate::std::gdt::cylindricity(e, a).map(|r| r.map(KclValue::continue_))),
225            StdFnProps::default("std::gdt::cylindricity"),
226        ),
227        ("gdt", "concentricity") => (
228            |e, a| Box::pin(crate::std::gdt::concentricity(e, a).map(|r| r.map(KclValue::continue_))),
229            StdFnProps::default("std::gdt::concentricity"),
230        ),
231        ("gdt", "symmetry") => (
232            |e, a| Box::pin(crate::std::gdt::symmetry(e, a).map(|r| r.map(KclValue::continue_))),
233            StdFnProps::default("std::gdt::symmetry"),
234        ),
235        ("gdt", "runout") => (
236            |e, a| Box::pin(crate::std::gdt::runout(e, a).map(|r| r.map(KclValue::continue_))),
237            StdFnProps::default("std::gdt::runout"),
238        ),
239        ("gdt", "angularity") => (
240            |e, a| Box::pin(crate::std::gdt::angularity(e, a).map(|r| r.map(KclValue::continue_))),
241            StdFnProps::default("std::gdt::angularity"),
242        ),
243        ("gdt", "perpendicularity") => (
244            |e, a| Box::pin(crate::std::gdt::perpendicularity(e, a).map(|r| r.map(KclValue::continue_))),
245            StdFnProps::default("std::gdt::perpendicularity"),
246        ),
247        ("gdt", "parallelism") => (
248            |e, a| Box::pin(crate::std::gdt::parallelism(e, a).map(|r| r.map(KclValue::continue_))),
249            StdFnProps::default("std::gdt::parallelism"),
250        ),
251        ("gdt", "annotation") => (
252            |e, a| Box::pin(crate::std::gdt::annotation(e, a).map(|r| r.map(KclValue::continue_))),
253            StdFnProps::default("std::gdt::annotation"),
254        ),
255        ("gdt", "note") => (
256            |e, a| Box::pin(crate::std::gdt::note(e, a).map(|r| r.map(KclValue::continue_))),
257            StdFnProps::default("std::gdt::note"),
258        ),
259        ("gdt", "distance") => (
260            |e, a| Box::pin(crate::std::gdt::distance(e, a).map(|r| r.map(KclValue::continue_))),
261            StdFnProps::default("std::gdt::distance"),
262        ),
263        ("gdt", "profile") => (
264            |e, a| Box::pin(crate::std::gdt::profile(e, a).map(|r| r.map(KclValue::continue_))),
265            StdFnProps::default("std::gdt::profile"),
266        ),
267        ("gdt", "profileLine") => (
268            |e, a| Box::pin(crate::std::gdt::profile_line(e, a).map(|r| r.map(KclValue::continue_))),
269            StdFnProps::default("std::gdt::profileLine"),
270        ),
271        ("gdt", "profileSurface") => (
272            |e, a| Box::pin(crate::std::gdt::profile_surface(e, a).map(|r| r.map(KclValue::continue_))),
273            StdFnProps::default("std::gdt::profileSurface"),
274        ),
275        ("gdt", "position") => (
276            |e, a| Box::pin(crate::std::gdt::position(e, a).map(|r| r.map(KclValue::continue_))),
277            StdFnProps::default("std::gdt::position"),
278        ),
279        ("math", "cos") => (
280            |e, a| Box::pin(crate::std::math::cos(e, a).map(|r| r.map(KclValue::continue_))),
281            StdFnProps::default("std::math::cos"),
282        ),
283        ("math", "sin") => (
284            |e, a| Box::pin(crate::std::math::sin(e, a).map(|r| r.map(KclValue::continue_))),
285            StdFnProps::default("std::math::sin"),
286        ),
287        ("math", "tan") => (
288            |e, a| Box::pin(crate::std::math::tan(e, a).map(|r| r.map(KclValue::continue_))),
289            StdFnProps::default("std::math::tan"),
290        ),
291        ("math", "acos") => (
292            |e, a| Box::pin(crate::std::math::acos(e, a).map(|r| r.map(KclValue::continue_))),
293            StdFnProps::default("std::math::acos"),
294        ),
295        ("math", "asin") => (
296            |e, a| Box::pin(crate::std::math::asin(e, a).map(|r| r.map(KclValue::continue_))),
297            StdFnProps::default("std::math::asin"),
298        ),
299        ("math", "atan") => (
300            |e, a| Box::pin(crate::std::math::atan(e, a).map(|r| r.map(KclValue::continue_))),
301            StdFnProps::default("std::math::atan"),
302        ),
303        ("math", "atan2") => (
304            |e, a| Box::pin(crate::std::math::atan2(e, a).map(|r| r.map(KclValue::continue_))),
305            StdFnProps::default("std::math::atan2"),
306        ),
307        ("math", "sqrt") => (
308            |e, a| Box::pin(crate::std::math::sqrt(e, a).map(|r| r.map(KclValue::continue_))),
309            StdFnProps::default("std::math::sqrt"),
310        ),
311
312        ("math", "abs") => (
313            |e, a| Box::pin(crate::std::math::abs(e, a).map(|r| r.map(KclValue::continue_))),
314            StdFnProps::default("std::math::abs"),
315        ),
316        ("math", "rem") => (
317            |e, a| Box::pin(crate::std::math::rem(e, a).map(|r| r.map(KclValue::continue_))),
318            StdFnProps::default("std::math::rem"),
319        ),
320        ("math", "round") => (
321            |e, a| Box::pin(crate::std::math::round(e, a).map(|r| r.map(KclValue::continue_))),
322            StdFnProps::default("std::math::round"),
323        ),
324        ("math", "floor") => (
325            |e, a| Box::pin(crate::std::math::floor(e, a).map(|r| r.map(KclValue::continue_))),
326            StdFnProps::default("std::math::floor"),
327        ),
328        ("math", "ceil") => (
329            |e, a| Box::pin(crate::std::math::ceil(e, a).map(|r| r.map(KclValue::continue_))),
330            StdFnProps::default("std::math::ceil"),
331        ),
332        ("math", "min") => (
333            |e, a| Box::pin(crate::std::math::min(e, a).map(|r| r.map(KclValue::continue_))),
334            StdFnProps::default("std::math::min"),
335        ),
336        ("math", "max") => (
337            |e, a| Box::pin(crate::std::math::max(e, a).map(|r| r.map(KclValue::continue_))),
338            StdFnProps::default("std::math::max"),
339        ),
340        ("math", "pow") => (
341            |e, a| Box::pin(crate::std::math::pow(e, a).map(|r| r.map(KclValue::continue_))),
342            StdFnProps::default("std::math::pow"),
343        ),
344        ("math", "log") => (
345            |e, a| Box::pin(crate::std::math::log(e, a).map(|r| r.map(KclValue::continue_))),
346            StdFnProps::default("std::math::log"),
347        ),
348        ("math", "log2") => (
349            |e, a| Box::pin(crate::std::math::log2(e, a).map(|r| r.map(KclValue::continue_))),
350            StdFnProps::default("std::math::log2"),
351        ),
352        ("math", "log10") => (
353            |e, a| Box::pin(crate::std::math::log10(e, a).map(|r| r.map(KclValue::continue_))),
354            StdFnProps::default("std::math::log10"),
355        ),
356        ("math", "ln") => (
357            |e, a| Box::pin(crate::std::math::ln(e, a).map(|r| r.map(KclValue::continue_))),
358            StdFnProps::default("std::math::ln"),
359        ),
360        ("math", "legLen") => (
361            |e, a| Box::pin(crate::std::math::leg_length(e, a).map(|r| r.map(KclValue::continue_))),
362            StdFnProps::default("std::math::legLen"),
363        ),
364        ("math", "legAngX") => (
365            |e, a| Box::pin(crate::std::math::leg_angle_x(e, a).map(|r| r.map(KclValue::continue_))),
366            StdFnProps::default("std::math::legAngX"),
367        ),
368        ("math", "legAngY") => (
369            |e, a| Box::pin(crate::std::math::leg_angle_y(e, a).map(|r| r.map(KclValue::continue_))),
370            StdFnProps::default("std::math::legAngY"),
371        ),
372        ("sketch", "circle") => (
373            |e, a| Box::pin(crate::std::shapes::circle(e, a).map(|r| r.map(KclValue::continue_))),
374            StdFnProps::default("std::sketch::circle").reads_regions_locally(),
375        ),
376        ("sketch", "ellipse") => (
377            |e, a| Box::pin(crate::std::shapes::ellipse(e, a).map(|r| r.map(KclValue::continue_))),
378            StdFnProps::default("std::sketch::ellipse").reads_regions_locally(),
379        ),
380        ("prelude", "helix") => (
381            |e, a| Box::pin(crate::std::helix::helix(e, a).map(|r| r.map(KclValue::continue_))),
382            StdFnProps::default("std::helix"),
383        ),
384        ("transform", "mirror2d") => (
385            |e, a| Box::pin(crate::std::mirror::mirror_2d(e, a).map(|r| r.map(KclValue::continue_))),
386            StdFnProps::default("std::transform::mirror2d"),
387        ),
388        ("transform", "mirror3d") => (
389            |e, a| Box::pin(crate::std::mirror::mirror_3d(e, a).map(|r| r.map(KclValue::continue_))),
390            StdFnProps::default("std::transform::mirror3d"),
391        ),
392        ("transform", "translate") => (
393            |e, a| Box::pin(crate::std::transform::translate(e, a).map(|r| r.map(KclValue::continue_))),
394            StdFnProps::default("std::transform::translate"),
395        ),
396        ("transform", "rotate") => (
397            |e, a| Box::pin(crate::std::transform::rotate(e, a).map(|r| r.map(KclValue::continue_))),
398            StdFnProps::default("std::transform::rotate"),
399        ),
400        ("transform", "scale") => (
401            |e, a| Box::pin(crate::std::transform::scale(e, a).map(|r| r.map(KclValue::continue_))),
402            StdFnProps::default("std::transform::scale"),
403        ),
404        ("transform", "hide") => (
405            |e, a| Box::pin(crate::std::transform::hide(e, a).map(|r| r.map(KclValue::continue_))),
406            StdFnProps::default("std::transform::hide").warn_deprecated_on_consumed_solid_args(),
407        ),
408        ("transform", "delete") => (
409            |e, a| Box::pin(crate::std::transform::delete(e, a).map(|r| r.map(KclValue::continue_))),
410            StdFnProps::default("std::transform::delete").consumes_regions(
411                ConsumedRegionArg::new(ConsumedRegionOperation::Delete)
412                    .deduplicate()
413                    .warn_if_already_consumed(),
414            ),
415        ),
416        ("prelude", "offsetPlane") => (
417            |e, a| Box::pin(crate::std::planes::offset_plane(e, a).map(|r| r.map(KclValue::continue_))),
418            StdFnProps::default("std::offsetPlane"),
419        ),
420        ("prelude", "assert") => (
421            |e, a| Box::pin(crate::std::assert::assert(e, a).map(|r| r.map(KclValue::continue_))),
422            StdFnProps::default("std::assert"),
423        ),
424        ("prelude", "assertIs") => (
425            |e, a| Box::pin(crate::std::assert::assert_is(e, a).map(|r| r.map(KclValue::continue_))),
426            StdFnProps::default("std::assertIs"),
427        ),
428        ("prelude", "fail") => (
429            |e, a| Box::pin(crate::std::fail::fail(e, a).map(|r| r.map(KclValue::continue_))),
430            StdFnProps::default("std::fail"),
431        ),
432        ("runtime", "exit") => (
433            |e, a| Box::pin(crate::std::runtime::exit(e, a)),
434            StdFnProps::default("std::runtime::exit"),
435        ),
436        ("string", "uppercase") => (
437            |e, a| Box::pin(crate::std::string::uppercase(e, a).map(|r| r.map(KclValue::continue_))),
438            StdFnProps::default("std::string::uppercase"),
439        ),
440        ("string", "lowercase") => (
441            |e, a| Box::pin(crate::std::string::lowercase(e, a).map(|r| r.map(KclValue::continue_))),
442            StdFnProps::default("std::string::lowercase"),
443        ),
444        ("string", "isEqual") => (
445            |e, a| Box::pin(crate::std::string::is_equal(e, a).map(|r| r.map(KclValue::continue_))),
446            StdFnProps::default("std::string::isEqual"),
447        ),
448        ("string", "trim") => (
449            |e, a| Box::pin(crate::std::string::trim(e, a).map(|r| r.map(KclValue::continue_))),
450            StdFnProps::default("std::string::trim"),
451        ),
452        ("string", "trimStart") => (
453            |e, a| Box::pin(crate::std::string::trim_start(e, a).map(|r| r.map(KclValue::continue_))),
454            StdFnProps::default("std::string::trimStart"),
455        ),
456        ("string", "trimEnd") => (
457            |e, a| Box::pin(crate::std::string::trim_end(e, a).map(|r| r.map(KclValue::continue_))),
458            StdFnProps::default("std::string::trimEnd"),
459        ),
460        ("string", "toString") => (
461            |e, a| Box::pin(crate::std::string::number_to_string(e, a).map(|r| r.map(KclValue::continue_))),
462            StdFnProps::default("std::string::toString"),
463        ),
464        ("solid", "fillet") => (
465            |e, a| Box::pin(crate::std::fillet::fillet(e, a).map(|r| r.map(KclValue::continue_))),
466            StdFnProps::default("std::solid::fillet"),
467        ),
468        ("solid", "chamfer") => (
469            |e, a| Box::pin(crate::std::chamfer::chamfer(e, a).map(|r| r.map(KclValue::continue_))),
470            StdFnProps::default("std::solid::chamfer"),
471        ),
472        ("solid", "shell") => (
473            |e, a| Box::pin(crate::std::shell::shell(e, a).map(|r| r.map(KclValue::continue_))),
474            StdFnProps::default("std::solid::shell"),
475        ),
476        ("solid", "hollow") => (
477            |e, a| Box::pin(crate::std::shell::hollow(e, a).map(|r| r.map(KclValue::continue_))),
478            StdFnProps::default("std::solid::hollow"),
479        ),
480        ("solid", "union") => (
481            |e, a| Box::pin(crate::std::csg::union(e, a).map(|r| r.map(KclValue::continue_))),
482            StdFnProps::default("std::solid::union"),
483        ),
484        ("solid", "intersect") => (
485            |e, a| Box::pin(crate::std::csg::intersect(e, a).map(|r| r.map(KclValue::continue_))),
486            StdFnProps::default("std::solid::intersect"),
487        ),
488        ("solid", "subtract") => (
489            |e, a| Box::pin(crate::std::csg::subtract(e, a).map(|r| r.map(KclValue::continue_))),
490            StdFnProps::default("std::solid::subtract"),
491        ),
492        ("solid", "patternTransform") => (
493            |e, a| Box::pin(crate::std::patterns::pattern_transform(e, a)),
494            StdFnProps::default("std::solid::patternTransform"),
495        ),
496        ("solid", "patternLinear3d") => (
497            |e, a| Box::pin(crate::std::patterns::pattern_linear_3d(e, a).map(|r| r.map(KclValue::continue_))),
498            StdFnProps::default("std::solid::patternLinear3d"),
499        ),
500        ("solid", "patternCircular3d") => (
501            |e, a| Box::pin(crate::std::patterns::pattern_circular_3d(e, a).map(|r| r.map(KclValue::continue_))),
502            StdFnProps::default("std::solid::patternCircular3d"),
503        ),
504        ("solid", "appearance") => (
505            |e, a| Box::pin(crate::std::appearance::appearance(e, a).map(|r| r.map(KclValue::continue_))),
506            StdFnProps::default("std::solid::appearance"),
507        ),
508        ("solid", "flipSurface") => (
509            |e, a| Box::pin(crate::std::surfaces::flip_surface(e, a).map(|r| r.map(KclValue::continue_))),
510            StdFnProps::default("std::solid::flipSurface"),
511        ),
512        ("solid", "split") => (
513            |e, a| Box::pin(crate::std::csg::split(e, a).map(|r| r.map(KclValue::continue_))),
514            StdFnProps::default("std::solid::split"),
515        ),
516        ("array", "map") => (
517            |e, a| Box::pin(crate::std::array::map(e, a)),
518            StdFnProps::default("std::array::map").reads_regions_locally(),
519        ),
520        ("array", "reduce") => (
521            |e, a| Box::pin(crate::std::array::reduce(e, a)),
522            StdFnProps::default("std::array::reduce").reads_regions_locally(),
523        ),
524        ("array", "push") => (
525            |e, a| Box::pin(crate::std::array::push(e, a).map(|r| r.map(KclValue::continue_))),
526            StdFnProps::default("std::array::push").reads_regions_locally(),
527        ),
528        ("array", "pop") => (
529            |e, a| Box::pin(crate::std::array::pop(e, a).map(|r| r.map(KclValue::continue_))),
530            StdFnProps::default("std::array::pop").reads_regions_locally(),
531        ),
532        ("array", "concat") => (
533            |e, a| Box::pin(crate::std::array::concat(e, a).map(|r| r.map(KclValue::continue_))),
534            StdFnProps::default("std::array::concat").reads_regions_locally(),
535        ),
536        ("array", "slice") => (
537            |e, a| Box::pin(crate::std::array::slice(e, a).map(|r| r.map(KclValue::continue_))),
538            StdFnProps::default("std::array::slice").reads_regions_locally(),
539        ),
540        ("array", "flatten") => (
541            |e, a| Box::pin(crate::std::array::flatten(e, a).map(|r| r.map(KclValue::continue_))),
542            StdFnProps::default("std::array::flatten")
543                .warn_deprecated_on_consumed_solid_args()
544                .reads_regions_locally(),
545        ),
546        ("prelude", "clone") => (
547            |e, a| Box::pin(crate::std::clone::clone(e, a).map(|r| r.map(KclValue::continue_))),
548            StdFnProps::default("std::clone"),
549        ),
550        ("prelude", "faceId") => (
551            |e, a| Box::pin(crate::std::ids::face_id(e, a).map(|r| r.map(KclValue::continue_))),
552            StdFnProps::default("std::faceId"),
553        ),
554        ("prelude", "edgeId") => (
555            |e, a| Box::pin(crate::std::ids::edge_id(e, a).map(|r| r.map(KclValue::continue_))),
556            StdFnProps::default("std::edgeId"),
557        ),
558        ("sketch", "conic") => (
559            |e, a| Box::pin(crate::std::sketch::conic(e, a).map(|r| r.map(KclValue::continue_))),
560            StdFnProps::default("std::sketch::conic"),
561        ),
562        ("sketch", "parabolic") => (
563            |e, a| Box::pin(crate::std::sketch::parabolic(e, a).map(|r| r.map(KclValue::continue_))),
564            StdFnProps::default("std::sketch::parabolic"),
565        ),
566        ("sketch", "parabolicPoint") => (
567            |e, a| Box::pin(crate::std::sketch::parabolic_point(e, a).map(|r| r.map(KclValue::continue_))),
568            StdFnProps::default("std::sketch::parabolicPoint"),
569        ),
570        ("sketch", "hyperbolic") => (
571            |e, a| Box::pin(crate::std::sketch::hyperbolic(e, a).map(|r| r.map(KclValue::continue_))),
572            StdFnProps::default("std::sketch::hyperbolic"),
573        ),
574        ("sketch", "hyperbolicPoint") => (
575            |e, a| Box::pin(crate::std::sketch::hyperbolic_point(e, a).map(|r| r.map(KclValue::continue_))),
576            StdFnProps::default("std::sketch::hyperbolicPoint"),
577        ),
578        ("sketch", "elliptic") => (
579            |e, a| Box::pin(crate::std::sketch::elliptic(e, a).map(|r| r.map(KclValue::continue_))),
580            StdFnProps::default("std::sketch::elliptic"),
581        ),
582        ("sketch", "ellipticPoint") => (
583            |e, a| Box::pin(crate::std::sketch::elliptic_point(e, a).map(|r| r.map(KclValue::continue_))),
584            StdFnProps::default("std::sketch::ellipticPoint"),
585        ),
586        ("sketch", "rectangle") => (
587            |e, a| Box::pin(crate::std::shapes::rectangle(e, a).map(|r| r.map(KclValue::continue_))),
588            StdFnProps::default("std::sketch::rectangle").reads_regions_locally(),
589        ),
590        ("sketch", "planeOf") => (
591            |e, a| Box::pin(crate::std::planes::plane_of(e, a).map(|r| r.map(KclValue::continue_))),
592            StdFnProps::default("std::sketch::planeOf"),
593        ),
594        ("sketch", "faceOf") => (
595            |e, a| Box::pin(crate::std::faces::face_of(e, a).map(|r| r.map(KclValue::continue_))),
596            StdFnProps::default("std::sketch::faceOf"),
597        ),
598        ("sketch", "extrude") => (
599            |e, a| Box::pin(crate::std::extrude::extrude(e, a).map(|r| r.map(KclValue::continue_))),
600            StdFnProps::default("std::sketch::extrude")
601                .consumes_regions(ConsumedRegionArg::new(ConsumedRegionOperation::Extrude).reject_alias_with("to")),
602        ),
603        ("sketch", "patternTransform2d") => (
604            |e, a| Box::pin(crate::std::patterns::pattern_transform_2d(e, a)),
605            StdFnProps::default("std::sketch::patternTransform2d"),
606        ),
607        ("sketch", "revolve") => (
608            |e, a| Box::pin(crate::std::revolve::revolve(e, a).map(|r| r.map(KclValue::continue_))),
609            StdFnProps::default("std::sketch::revolve")
610                .consumes_regions(ConsumedRegionArg::new(ConsumedRegionOperation::Revolve)),
611        ),
612        ("sketch", "sweep") => (
613            |e, a| Box::pin(crate::std::sweep::sweep(e, a).map(|r| r.map(KclValue::continue_))),
614            StdFnProps::default("std::sketch::sweep")
615                .consumes_regions(ConsumedRegionArg::new(ConsumedRegionOperation::Sweep).preserve_alias_with("path")),
616        ),
617        ("sketch", "loft") => (
618            |e, a| Box::pin(crate::std::loft::loft(e, a).map(|r| r.map(KclValue::continue_))),
619            StdFnProps::default("std::sketch::loft"),
620        ),
621        ("sketch", "polygon") => (
622            |e, a| Box::pin(crate::std::shapes::polygon(e, a).map(|r| r.map(KclValue::continue_))),
623            StdFnProps::default("std::sketch::polygon").reads_regions_locally(),
624        ),
625        ("sketch", "circleThreePoint") => (
626            |e, a| Box::pin(crate::std::shapes::circle_three_point(e, a).map(|r| r.map(KclValue::continue_))),
627            StdFnProps::default("std::sketch::circleThreePoint").reads_regions_locally(),
628        ),
629        ("sketch", "getCommonEdge") => (
630            |e, a| Box::pin(crate::std::edge::get_common_edge(e, a).map(|r| r.map(KclValue::continue_))),
631            StdFnProps::default("std::sketch::getCommonEdge"),
632        ),
633        ("sketch", "getBoundedEdge") => (
634            |e, a| Box::pin(crate::std::edge::get_bounded_edge(e, a).map(|r| r.map(KclValue::continue_))),
635            StdFnProps::default("std::sketch::getBoundedEdge"),
636        ),
637        ("sketch", "getNextAdjacentEdge") => (
638            |e, a| Box::pin(crate::std::edge::get_next_adjacent_edge(e, a).map(|r| r.map(KclValue::continue_))),
639            StdFnProps::default("std::sketch::getNextAdjacentEdge"),
640        ),
641        ("sketch", "getOppositeEdge") => (
642            |e, a| Box::pin(crate::std::edge::get_opposite_edge(e, a).map(|r| r.map(KclValue::continue_))),
643            StdFnProps::default("std::sketch::getOppositeEdge"),
644        ),
645        ("sketch", "getPreviousAdjacentEdge") => (
646            |e, a| Box::pin(crate::std::edge::get_previous_adjacent_edge(e, a).map(|r| r.map(KclValue::continue_))),
647            StdFnProps::default("std::sketch::getPreviousAdjacentEdge"),
648        ),
649        ("sketch", "patternLinear2d") => (
650            |e, a| Box::pin(crate::std::patterns::pattern_linear_2d(e, a).map(|r| r.map(KclValue::continue_))),
651            StdFnProps::default("std::sketch::patternLinear2d"),
652        ),
653        ("sketch", "patternCircular2d") => (
654            |e, a| Box::pin(crate::std::patterns::pattern_circular_2d(e, a).map(|r| r.map(KclValue::continue_))),
655            StdFnProps::default("std::sketch::patternCircular2d"),
656        ),
657        ("sketch", "segEnd") => (
658            |e, a| Box::pin(crate::std::segment::segment_end(e, a).map(|r| r.map(KclValue::continue_))),
659            StdFnProps::default("std::sketch::segEnd"),
660        ),
661        ("sketch", "segEndX") => (
662            |e, a| Box::pin(crate::std::segment::segment_end_x(e, a).map(|r| r.map(KclValue::continue_))),
663            StdFnProps::default("std::sketch::segEndX"),
664        ),
665        ("sketch", "segEndY") => (
666            |e, a| Box::pin(crate::std::segment::segment_end_y(e, a).map(|r| r.map(KclValue::continue_))),
667            StdFnProps::default("std::sketch::segEndY"),
668        ),
669        ("sketch", "segStart") => (
670            |e, a| Box::pin(crate::std::segment::segment_start(e, a).map(|r| r.map(KclValue::continue_))),
671            StdFnProps::default("std::sketch::segStart"),
672        ),
673        ("sketch", "segStartX") => (
674            |e, a| Box::pin(crate::std::segment::segment_start_x(e, a).map(|r| r.map(KclValue::continue_))),
675            StdFnProps::default("std::sketch::segStartX"),
676        ),
677        ("sketch", "segStartY") => (
678            |e, a| Box::pin(crate::std::segment::segment_start_y(e, a).map(|r| r.map(KclValue::continue_))),
679            StdFnProps::default("std::sketch::segStartY"),
680        ),
681        ("sketch", "lastSegX") => (
682            |e, a| Box::pin(crate::std::segment::last_segment_x(e, a).map(|r| r.map(KclValue::continue_))),
683            StdFnProps::default("std::sketch::lastSegX").reads_regions_locally(),
684        ),
685        ("sketch", "lastSegY") => (
686            |e, a| Box::pin(crate::std::segment::last_segment_y(e, a).map(|r| r.map(KclValue::continue_))),
687            StdFnProps::default("std::sketch::lastSegY").reads_regions_locally(),
688        ),
689        ("sketch", "segLen") => (
690            |e, a| Box::pin(crate::std::segment::segment_length(e, a).map(|r| r.map(KclValue::continue_))),
691            StdFnProps::default("std::sketch::segLen"),
692        ),
693        ("sketch", "segAng") => (
694            |e, a| Box::pin(crate::std::segment::segment_angle(e, a).map(|r| r.map(KclValue::continue_))),
695            StdFnProps::default("std::sketch::segAng"),
696        ),
697        ("sketch", "tangentToEnd") => (
698            |e, a| Box::pin(crate::std::segment::tangent_to_end(e, a).map(|r| r.map(KclValue::continue_))),
699            StdFnProps::default("std::sketch::tangentToEnd"),
700        ),
701        ("sketch", "profileStart") => (
702            |e, a| Box::pin(crate::std::sketch::profile_start(e, a).map(|r| r.map(KclValue::continue_))),
703            StdFnProps::default("std::sketch::profileStart").reads_regions_locally(),
704        ),
705        ("sketch", "profileStartX") => (
706            |e, a| Box::pin(crate::std::sketch::profile_start_x(e, a).map(|r| r.map(KclValue::continue_))),
707            StdFnProps::default("std::sketch::profileStartX").reads_regions_locally(),
708        ),
709        ("sketch", "profileStartY") => (
710            |e, a| Box::pin(crate::std::sketch::profile_start_y(e, a).map(|r| r.map(KclValue::continue_))),
711            StdFnProps::default("std::sketch::profileStartY").reads_regions_locally(),
712        ),
713        ("sketch", "startSketchOn") => (
714            |e, a| Box::pin(crate::std::sketch::start_sketch_on(e, a).map(|r| r.map(KclValue::continue_))),
715            StdFnProps::default("std::sketch::startSketchOn"),
716        ),
717        ("sketch", "startProfile") => (
718            |e, a| Box::pin(crate::std::sketch::start_profile(e, a).map(|r| r.map(KclValue::continue_))),
719            StdFnProps::default("std::sketch::startProfile"),
720        ),
721        ("sketch", "involuteCircular") => (
722            |e, a| Box::pin(crate::std::sketch::involute_circular(e, a).map(|r| r.map(KclValue::continue_))),
723            StdFnProps::default("std::sketch::involuteCircular"),
724        ),
725        ("sketch", "line") => (
726            |e, a| Box::pin(crate::std::sketch::line(e, a).map(|r| r.map(KclValue::continue_))),
727            StdFnProps::default("std::sketch::line"),
728        ),
729        ("sketch", "xLine") => (
730            |e, a| Box::pin(crate::std::sketch::x_line(e, a).map(|r| r.map(KclValue::continue_))),
731            StdFnProps::default("std::sketch::xLine"),
732        ),
733        ("sketch", "yLine") => (
734            |e, a| Box::pin(crate::std::sketch::y_line(e, a).map(|r| r.map(KclValue::continue_))),
735            StdFnProps::default("std::sketch::yLine"),
736        ),
737        ("sketch", "angledLine") => (
738            |e, a| Box::pin(crate::std::sketch::angled_line(e, a).map(|r| r.map(KclValue::continue_))),
739            StdFnProps::default("std::sketch::angledLine"),
740        ),
741        ("sketch", "angledLineThatIntersects") => (
742            |e, a| Box::pin(crate::std::sketch::angled_line_that_intersects(e, a).map(|r| r.map(KclValue::continue_))),
743            StdFnProps::default("std::sketch::angledLineThatIntersects"),
744        ),
745        ("sketch", "close") => (
746            |e, a| Box::pin(crate::std::sketch::close(e, a).map(|r| r.map(KclValue::continue_))),
747            StdFnProps::default("std::sketch::close"),
748        ),
749        ("sketch", "arc") => (
750            |e, a| Box::pin(crate::std::sketch::arc(e, a).map(|r| r.map(KclValue::continue_))),
751            StdFnProps::default("std::sketch::arc"),
752        ),
753        ("sketch", "tangentialArc") => (
754            |e, a| Box::pin(crate::std::sketch::tangential_arc(e, a).map(|r| r.map(KclValue::continue_))),
755            StdFnProps::default("std::sketch::tangentialArc"),
756        ),
757        ("sketch", "bezierCurve") => (
758            |e, a| Box::pin(crate::std::sketch::bezier_curve(e, a).map(|r| r.map(KclValue::continue_))),
759            StdFnProps::default("std::sketch::bezierCurve"),
760        ),
761        ("sketch", "subtract2d") => (
762            |e, a| Box::pin(crate::std::sketch::subtract_2d(e, a).map(|r| r.map(KclValue::continue_))),
763            StdFnProps::default("std::sketch::subtract2d"),
764        ),
765        ("appearance", "hexString") => (
766            |e, a| Box::pin(crate::std::appearance::hex_string(e, a).map(|r| r.map(KclValue::continue_))),
767            StdFnProps::default("std::appearance::hexString"),
768        ),
769        ("solver", "point") => (
770            |e, a| Box::pin(crate::std::constraints::point(e, a).map(|r| r.map(KclValue::continue_))),
771            StdFnProps::default("std::solver::point"),
772        ),
773        ("solver", "line") => (
774            |e, a| Box::pin(crate::std::constraints::line(e, a).map(|r| r.map(KclValue::continue_))),
775            StdFnProps::default("std::solver::line"),
776        ),
777        ("solver", "arc") => (
778            |e, a| Box::pin(crate::std::constraints::arc(e, a).map(|r| r.map(KclValue::continue_))),
779            StdFnProps::default("std::solver::arc"),
780        ),
781        ("solver", "circle") => (
782            |e, a| Box::pin(crate::std::constraints::circle(e, a).map(|r| r.map(KclValue::continue_))),
783            StdFnProps::default("std::solver::circle"),
784        ),
785        ("solver", "controlPointSpline") => (
786            |e, a| Box::pin(crate::std::constraints::control_point_spline(e, a).map(|r| r.map(KclValue::continue_))),
787            StdFnProps::default("std::solver::controlPointSpline"),
788        ),
789        ("solver", "coincident") => (
790            |e, a| Box::pin(crate::std::constraints::coincident(e, a).map(|r| r.map(KclValue::continue_))),
791            StdFnProps::default("std::solver::coincident"),
792        ),
793        ("solver", "distance") => (
794            |e, a| Box::pin(crate::std::constraints::distance(e, a).map(|r| r.map(KclValue::continue_))),
795            StdFnProps::default("std::solver::distance"),
796        ),
797        ("solver", "radius") => (
798            |e, a| Box::pin(crate::std::constraints::radius(e, a).map(|r| r.map(KclValue::continue_))),
799            StdFnProps::default("std::solver::radius"),
800        ),
801        ("solver", "diameter") => (
802            |e, a| Box::pin(crate::std::constraints::diameter(e, a).map(|r| r.map(KclValue::continue_))),
803            StdFnProps::default("std::solver::diameter"),
804        ),
805        ("solver", "horizontalDistance") => (
806            |e, a| Box::pin(crate::std::constraints::horizontal_distance(e, a).map(|r| r.map(KclValue::continue_))),
807            StdFnProps::default("std::solver::horizontalDistance"),
808        ),
809        ("solver", "verticalDistance") => (
810            |e, a| Box::pin(crate::std::constraints::vertical_distance(e, a).map(|r| r.map(KclValue::continue_))),
811            StdFnProps::default("std::solver::verticalDistance"),
812        ),
813        ("solver", "equalLength") => (
814            |e, a| Box::pin(crate::std::constraints::equal_length(e, a).map(|r| r.map(KclValue::continue_))),
815            StdFnProps::default("std::solver::equalLength"),
816        ),
817        ("solver", "midpoint") => (
818            |e, a| Box::pin(crate::std::constraints::midpoint(e, a).map(|r| r.map(KclValue::continue_))),
819            StdFnProps::default("std::solver::midpoint"),
820        ),
821        ("solver", "equalRadius") => (
822            |e, a| Box::pin(crate::std::constraints::equal_radius(e, a).map(|r| r.map(KclValue::continue_))),
823            StdFnProps::default("std::solver::equalRadius"),
824        ),
825        ("solver", "angle") => (
826            |e, a| Box::pin(crate::std::constraints::angle(e, a).map(|r| r.map(KclValue::continue_))),
827            StdFnProps::default("std::solver::angle"),
828        ),
829        ("solver", "angleDimension") => (
830            |e, a| Box::pin(crate::std::constraints::angle_dimension(e, a).map(|r| r.map(KclValue::continue_))),
831            StdFnProps::default("std::solver::angleDimension"),
832        ),
833        ("solver", "tangent") => (
834            |e, a| Box::pin(crate::std::constraints::tangent(e, a).map(|r| r.map(KclValue::continue_))),
835            StdFnProps::default("std::solver::tangent"),
836        ),
837        ("solver", "symmetric") => (
838            |e, a| Box::pin(crate::std::constraints::symmetric(e, a).map(|r| r.map(KclValue::continue_))),
839            StdFnProps::default("std::solver::symmetric"),
840        ),
841        ("solver", "horizontal") => (
842            |e, a| Box::pin(crate::std::constraints::horizontal(e, a).map(|r| r.map(KclValue::continue_))),
843            StdFnProps::default("std::solver::horizontal"),
844        ),
845        ("solver", "parallel") => (
846            |e, a| Box::pin(crate::std::constraints::parallel(e, a).map(|r| r.map(KclValue::continue_))),
847            StdFnProps::default("std::solver::parallel"),
848        ),
849        ("solver", "perpendicular") => (
850            |e, a| Box::pin(crate::std::constraints::perpendicular(e, a).map(|r| r.map(KclValue::continue_))),
851            StdFnProps::default("std::solver::perpendicular"),
852        ),
853        ("solver", "vertical") => (
854            |e, a| Box::pin(crate::std::constraints::vertical(e, a).map(|r| r.map(KclValue::continue_))),
855            StdFnProps::default("std::solver::vertical"),
856        ),
857        ("sketch", "region") => (
858            |e, a| Box::pin(crate::std::sketch::region(e, a).map(|r| r.map(KclValue::continue_))),
859            StdFnProps::default("std::sketch::region"),
860        ),
861        ("solid", "isSurface") => (
862            |e, a| Box::pin(crate::std::surfaces::is_surface(e, a).map(|r| r.map(KclValue::continue_))),
863            StdFnProps::default("std::solid::isSurface"),
864        ),
865        ("solid", "isSolid") => (
866            |e, a| Box::pin(crate::std::surfaces::is_solid(e, a).map(|r| r.map(KclValue::continue_))),
867            StdFnProps::default("std::solid::isSolid"),
868        ),
869        ("solid", "deleteFace") => (
870            |e, a| Box::pin(crate::std::surfaces::delete_face(e, a).map(|r| r.map(KclValue::continue_))),
871            StdFnProps::default("std::solid::deleteFace"),
872        ),
873        ("solid", "blend") => (
874            |e, a| Box::pin(crate::std::surfaces::blend(e, a).map(|r| r.map(KclValue::continue_))),
875            StdFnProps::default("std::solid::blend"),
876        ),
877        ("solid", "joinSurfaces") => (
878            |e, a| Box::pin(crate::std::surfaces::join(e, a).map(|r| r.map(KclValue::continue_))),
879            StdFnProps::default("std::solid::joinSurfaces"),
880        ),
881        ("view", "oriented") => (
882            |e, a| Box::pin(crate::std::view::oriented(e, a).map(|r| r.map(KclValue::continue_))),
883            StdFnProps::default("std::view::oriented"),
884        ),
885        ("view", "directed") => (
886            |e, a| Box::pin(crate::std::view::directed(e, a).map(|r| r.map(KclValue::continue_))),
887            StdFnProps::default("std::view::directed"),
888        ),
889        (module, fn_name) => {
890            panic!("No implementation found for {module}::{fn_name}, please add it to this big match statement")
891        }
892    }
893}
894
895pub(crate) fn std_ty(path: &str, fn_name: &str) -> (PrimitiveType, StdFnProps) {
896    match (path, fn_name) {
897        ("types", "Segment") => (PrimitiveType::Segment, StdFnProps::default("std::types::Segment")),
898        ("types", "Sketch") => (PrimitiveType::Sketch, StdFnProps::default("std::types::Sketch")),
899        ("types", "Solid") => (PrimitiveType::Solid, StdFnProps::default("std::types::Solid")),
900        ("types", "Plane") => (PrimitiveType::Plane, StdFnProps::default("std::types::Plane")),
901        ("types", "Face") => (PrimitiveType::Face, StdFnProps::default("std::types::Face")),
902        ("types", "GdtAnnotation") => (
903            PrimitiveType::GdtAnnotation,
904            StdFnProps::default("std::types::GdtAnnotation"),
905        ),
906        ("types", "Helix") => (PrimitiveType::Helix, StdFnProps::default("std::types::Helix")),
907        ("types", "Edge") => (PrimitiveType::Edge, StdFnProps::default("std::types::Edge")),
908        ("types", "Axis2d") => (PrimitiveType::Axis2d, StdFnProps::default("std::types::Axis2d")),
909        ("types", "Axis3d") => (PrimitiveType::Axis3d, StdFnProps::default("std::types::Axis3d")),
910        ("types", "TaggedEdge") => (PrimitiveType::TaggedEdge, StdFnProps::default("std::types::TaggedEdge")),
911        ("types", "TaggedFace") => (PrimitiveType::TaggedFace, StdFnProps::default("std::types::TaggedFace")),
912        ("types", "BoundedEdge") => (
913            PrimitiveType::BoundedEdge,
914            StdFnProps::default("std::types::BoundedEdge"),
915        ),
916        ("view", "CameraView") => (PrimitiveType::CameraView, StdFnProps::default("std::view::CameraView")),
917        ("view", "NamedView") => (PrimitiveType::NamedView, StdFnProps::default("std::view::NamedView")),
918        _ => unreachable!(),
919    }
920}
921
922/// The default tolerance for modeling commands in millimeters.
923const DEFAULT_TOLERANCE_MM: f64 = 0.0000001;
924
925/// The default tolerance for testing the equality of points.
926/// WARNING: This must match the tolerance in engine/cpp/engine/scene/constants.h
927#[allow(clippy::excessive_precision)]
928const EQUAL_POINTS_DIST_EPSILON: f64 = 2.3283064365386962890625e-10;
929
930#[derive(Debug, Clone, Copy, PartialEq, Eq)]
931pub(crate) enum CircularDirection {
932    Counterclockwise,
933    Clockwise,
934}
935
936impl CircularDirection {
937    pub fn is_clockwise(self) -> bool {
938        match self {
939            CircularDirection::Counterclockwise => false,
940            CircularDirection::Clockwise => true,
941        }
942    }
943}