1use std::num::NonZeroU32;
2
3use anyhow::Result;
4use kcl_api::Number;
5use kcl_api::NumericSuffixTypeConvertError;
6use kcl_api::UnitAngle;
7use kcl_api::UnitLength;
8use kcmc::shared::BodyType;
9use kittycad_modeling_cmds as kcmc;
10use serde::Serialize;
11use uuid::Uuid;
12
13use super::fillet::EdgeReference;
14use crate::CompilationIssue;
15use crate::MetaSettings;
16use crate::ModuleId;
17use crate::SourceRange;
18use crate::errors::KclError;
19use crate::errors::KclErrorDetails;
20use crate::execution::BoundedEdge;
21use crate::execution::ExecState;
22use crate::execution::Extrudable;
23use crate::execution::ExtrudeSurface;
24use crate::execution::Face;
25use crate::execution::Geometry;
26use crate::execution::HasAppearance;
27use crate::execution::Helix;
28use crate::execution::KclObjectFields;
29use crate::execution::KclValue;
30use crate::execution::Metadata;
31use crate::execution::Plane;
32use crate::execution::PlaneInfo;
33use crate::execution::Segment;
34use crate::execution::Sketch;
35use crate::execution::SketchSurface;
36use crate::execution::Solid;
37use crate::execution::TagIdentifier;
38use crate::execution::annotations;
39pub use crate::execution::fn_call::Args;
40use crate::execution::kcl_value::FunctionSource;
41use crate::execution::types::CoercionMode;
42use crate::execution::types::NumericType;
43use crate::execution::types::NumericTypeExt;
44use crate::execution::types::PrimitiveType;
45use crate::execution::types::RuntimeType;
46use crate::execution::types::UnitType;
47use crate::parsing::ast::types::TagNode;
48use crate::std::CircularDirection;
49use crate::std::edge::check_tag_not_ambiguous;
50use crate::std::shapes::PolygonType;
51use crate::std::shapes::SketchOrSurface;
52use crate::std::sketch::FaceTag;
53use crate::std::sweep::SweepPath;
54
55const ERROR_STRING_SKETCH_TO_SOLID_HELPER: &str =
56 "You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`";
57
58#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
59#[ts(export)]
60#[serde(rename_all = "camelCase")]
61pub struct TyF64 {
62 pub n: f64,
63 pub ty: NumericType,
64}
65
66impl TyF64 {
67 pub const fn new(n: f64, ty: NumericType) -> Self {
68 Self { n, ty }
69 }
70
71 pub fn from_number(n: Number, settings: &MetaSettings) -> Self {
72 Self {
73 n: n.value,
74 ty: NumericType::from_parsed(n.units, settings),
75 }
76 }
77
78 pub fn unwrap_to_mm(&self) -> f64 {
81 self.unwrap_to_length_units(UnitLength::Millimeters)
82 }
83
84 pub fn to_mm(&self) -> Option<f64> {
86 self.to_length_units(UnitLength::Millimeters)
87 }
88
89 pub fn is_length_compatible(&self) -> bool {
91 #[expect(
92 clippy::match_like_matches_macro,
93 reason = "Want to mirror the structure of `to_length_units` below"
94 )]
95 match self.ty {
96 NumericType::Default { .. } => true,
97 NumericType::Known(UnitType::Length(_)) => true,
98 _ => false,
99 }
100 }
101
102 pub fn unwrap_to_length_units(&self, units: UnitLength) -> f64 {
105 self.to_length_units(units)
106 .unwrap_or_else(|| panic!("expected length, found {:?}", self.ty))
107 }
108
109 pub fn to_length_units(&self, units: UnitLength) -> Option<f64> {
112 let len = match &self.ty {
113 NumericType::Default { len, .. } => *len,
114 NumericType::Known(UnitType::Length(len)) => *len,
115 _ => return None,
116 };
117
118 Some(crate::execution::types::adjust_length(len, self.n, units).0)
119 }
120
121 pub fn unwrap_to_degrees(&self, exec_state: &mut ExecState, source_range: SourceRange) -> f64 {
124 self.to_degrees(exec_state, source_range)
125 .unwrap_or_else(|| panic!("expected angle, found {:?}", self.ty))
126 }
127
128 pub fn to_degrees(&self, exec_state: &mut ExecState, source_range: SourceRange) -> Option<f64> {
131 let angle = match self.ty {
132 NumericType::Default { angle, .. } => {
133 if self.n != 0.0 {
134 exec_state.warn(
135 CompilationIssue::err(source_range, "Prefer to use explicit units for angles"),
136 annotations::WARN_ANGLE_UNITS,
137 );
138 }
139 angle
140 }
141 NumericType::Known(UnitType::Angle(angle)) => angle,
142 _ => return None,
143 };
144
145 Some(crate::execution::types::adjust_angle(angle, self.n, UnitAngle::Degrees).0)
146 }
147
148 pub fn unwrap_to_radians(&self, exec_state: &mut ExecState, source_range: SourceRange) -> f64 {
151 self.to_radians(exec_state, source_range)
152 .unwrap_or_else(|| panic!("expected angle, found {:?}", self.ty))
153 }
154
155 pub fn to_radians(&self, exec_state: &mut ExecState, source_range: SourceRange) -> Option<f64> {
158 let angle = match self.ty {
159 NumericType::Default { angle, .. } => {
160 if self.n != 0.0 {
161 exec_state.warn(
162 CompilationIssue::err(source_range, "Prefer to use explicit units for angles"),
163 annotations::WARN_ANGLE_UNITS,
164 );
165 }
166 angle
167 }
168 NumericType::Known(UnitType::Angle(angle)) => angle,
169 _ => return None,
170 };
171
172 Some(crate::execution::types::adjust_angle(angle, self.n, UnitAngle::Radians).0)
173 }
174
175 pub fn count(n: f64) -> Self {
176 Self {
177 n,
178 ty: NumericType::count(),
179 }
180 }
181
182 pub fn map_value(mut self, n: f64) -> Self {
183 self.n = n;
184 self
185 }
186
187 pub fn to_point2d(value: &[TyF64; 2]) -> Result<kcl_api::Point2d<Number>, NumericSuffixTypeConvertError> {
190 Ok(kcl_api::Point2d {
191 x: Number {
192 value: value[0].n,
193 units: value[0].ty.try_into()?,
194 },
195 y: Number {
196 value: value[1].n,
197 units: value[1].ty.try_into()?,
198 },
199 })
200 }
201}
202
203fn is_lengths(nums: &[TyF64]) -> bool {
205 nums.iter().all(|num| num.is_length_compatible())
206}
207
208impl Args {
209 pub(crate) fn get_kw_arg_opt<T>(
210 &self,
211 label: &str,
212 ty: &RuntimeType,
213 exec_state: &mut ExecState,
214 ) -> Result<Option<T>, KclError>
215 where
216 T: for<'a> FromKclValue<'a>,
217 {
218 match self.labeled.get(label) {
219 None => return Ok(None),
220 Some(a) => {
221 if let KclValue::KclNone { .. } = &a.value {
222 return Ok(None);
223 }
224 }
225 }
226
227 self.get_kw_arg(label, ty, exec_state).map(Some)
228 }
229
230 pub(crate) fn get_kw_arg<T>(&self, label: &str, ty: &RuntimeType, exec_state: &mut ExecState) -> Result<T, KclError>
231 where
232 T: for<'a> FromKclValue<'a>,
233 {
234 let Some(arg) = self.labeled.get(label) else {
235 return Err(KclError::new_semantic(KclErrorDetails::new(
236 if let Some(ref fname) = self.fn_name {
237 format!("The `{fname}` function requires a keyword argument `{label}`")
238 } else {
239 format!("This function requires a keyword argument `{label}`")
240 },
241 vec![self.source_range],
242 )));
243 };
244
245 let arg = arg.value.coerce(ty, CoercionMode::implicit(), exec_state).map_err(|_| {
246 let actual_type = arg.value.principal_type();
247 let actual_type_name = actual_type
248 .as_ref()
249 .map(|t| t.to_string())
250 .unwrap_or_else(|| arg.value.human_friendly_type());
251 let msg_base = if let Some(ref fname) = self.fn_name {
252 format!("The `{fname}` function expected its `{label}` argument to be {} but it's actually of type {actual_type_name}", ty.human_friendly_type())
253 } else {
254 format!("This function expected its `{label}` argument to be {} but it's actually of type {actual_type_name}", ty.human_friendly_type())
255 };
256 let suggestion = match (ty, actual_type) {
257 (RuntimeType::Primitive(PrimitiveType::Solid), Some(RuntimeType::Primitive(PrimitiveType::Sketch))) => {
258 Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER)
259 }
260 (RuntimeType::Array(t, _), Some(RuntimeType::Primitive(PrimitiveType::Sketch)))
261 if **t == RuntimeType::Primitive(PrimitiveType::Solid) =>
262 {
263 Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER)
264 }
265 _ => None,
266 };
267 let mut message = match suggestion {
268 None => msg_base,
269 Some(sugg) => format!("{msg_base}. {sugg}"),
270 };
271 if message.contains("one or more Solids or ImportedGeometry") && message.contains("actually of type Sketch") {
272 message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
273 }
274 KclError::new_semantic(KclErrorDetails::new(message, arg.source_ranges()))
275 })?;
276
277 T::from_kcl_val(&arg).ok_or_else(|| {
278 KclError::new_internal(KclErrorDetails::new(
279 format!("Mismatch between type coercion and value extraction (this isn't your fault).\nTo assist in bug-reporting, expected type: {ty:?}; actual value: {arg:?}"),
280 vec![self.source_range],
281 ))
282 })
283 }
284
285 pub(crate) fn kw_arg_edge_array_and_source(
288 &self,
289 label: &str,
290 ) -> Result<Vec<(EdgeReference, SourceRange)>, KclError> {
291 let Some(arg) = self.labeled.get(label) else {
292 let err = KclError::new_semantic(KclErrorDetails::new(
293 if let Some(ref fname) = self.fn_name {
294 format!("The `{fname}` function requires a keyword argument '{label}'")
295 } else {
296 format!("This function requires a keyword argument '{label}'")
297 },
298 vec![self.source_range],
299 ));
300 return Err(err);
301 };
302 arg.value
303 .clone()
304 .into_array()
305 .iter()
306 .map(|item| {
307 let source = SourceRange::from(item);
308 let val = FromKclValue::from_kcl_val(item).ok_or_else(|| {
309 KclError::new_semantic(KclErrorDetails::new(
310 format!("Expected an Edge but found {}", arg.value.human_friendly_type()),
311 arg.source_ranges(),
312 ))
313 })?;
314 Ok((val, source))
315 })
316 .collect::<Result<Vec<_>, _>>()
317 }
318
319 pub(crate) fn kw_arg_edge_array_and_source_opt(
320 &self,
321 label: &str,
322 ) -> Result<Option<Vec<(EdgeReference, SourceRange)>>, KclError> {
323 if !self.labeled.contains_key(label) {
324 return Ok(None);
325 }
326
327 self.kw_arg_edge_array_and_source(label).map(Some)
328 }
329
330 pub(crate) fn get_unlabeled_kw_arg_array_and_type(
331 &self,
332 label: &str,
333 exec_state: &mut ExecState,
334 ) -> Result<(Vec<KclValue>, RuntimeType), KclError> {
335 let value = self.get_unlabeled_kw_arg(label, &RuntimeType::any_array(), exec_state)?;
336 Ok(match value {
337 KclValue::HomArray { value, ty } => (value, ty),
338 KclValue::Tuple { value, .. } => (value, RuntimeType::any()),
339 val => (vec![val], RuntimeType::any()),
340 })
341 }
342
343 pub(crate) fn get_unlabeled_kw_arg<T>(
346 &self,
347 label: &str,
348 ty: &RuntimeType,
349 exec_state: &mut ExecState,
350 ) -> Result<T, KclError>
351 where
352 T: for<'a> FromKclValue<'a>,
353 {
354 let arg = self
355 .unlabeled_kw_arg_unconverted()
356 .ok_or(KclError::new_semantic(KclErrorDetails::new(
357 if let Some(ref fname) = self.fn_name {
358 format!(
359 "The `{fname}` function requires a value for the special unlabeled first parameter, '{label}'"
360 )
361 } else {
362 format!("This function requires a value for the special unlabeled first parameter, '{label}'")
363 },
364 vec![self.source_range],
365 )))?;
366
367 let arg = arg.value.coerce(ty, CoercionMode::implicit(), exec_state).map_err(|_| {
368 let actual_type = arg.value.principal_type();
369 let actual_type_name = actual_type
370 .as_ref()
371 .map(|t| t.to_string())
372 .unwrap_or_else(|| arg.value.human_friendly_type());
373 let msg_base = if let Some(ref fname) = self.fn_name {
374 format!(
375 "The `{fname}` function expected the input argument to be {} but it's actually of type {actual_type_name}",
376 ty.human_friendly_type(),
377 )
378 } else {
379 format!(
380 "This function expected the input argument to be {} but it's actually of type {actual_type_name}",
381 ty.human_friendly_type(),
382 )
383 };
384 let suggestion = match (ty, actual_type) {
385 (RuntimeType::Primitive(PrimitiveType::Solid), Some(RuntimeType::Primitive(PrimitiveType::Sketch))) => {
386 Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER)
387 }
388 (RuntimeType::Array(ty, _), Some(RuntimeType::Primitive(PrimitiveType::Sketch)))
389 if **ty == RuntimeType::Primitive(PrimitiveType::Solid) =>
390 {
391 Some(ERROR_STRING_SKETCH_TO_SOLID_HELPER)
392 }
393 _ => None,
394 };
395 let mut message = match suggestion {
396 None => msg_base,
397 Some(sugg) => format!("{msg_base}. {sugg}"),
398 };
399
400 if message.contains("one or more Solids or ImportedGeometry") && message.contains("actually of type Sketch") {
401 message = format!("{message}. {ERROR_STRING_SKETCH_TO_SOLID_HELPER}");
402 }
403 KclError::new_semantic(KclErrorDetails::new(message, arg.source_ranges()))
404 })?;
405
406 T::from_kcl_val(&arg).ok_or_else(|| {
407 KclError::new_internal(KclErrorDetails::new(
408 format!("Mismatch between type coercion and value extraction (this isn't your fault).\nTo assist in bug-reporting, expected type: {ty:?}; actual value: {arg:?}"),
409 vec![self.source_range],
410 ))
411 })
412 }
413
414 fn get_tag_info_from_memory(
416 &self,
417 exec_state: &mut ExecState,
418 tag: &TagIdentifier,
419 ) -> Result<crate::execution::TagEngineInfo, KclError> {
420 match exec_state.stack().get_from_call_stack(&tag.value, self.source_range)? {
421 (epoch, KclValue::TagIdentifier(t)) => {
422 let info = t.get_info(epoch).ok_or_else(|| {
423 KclError::new_type(KclErrorDetails::new(
424 format!("Tag `{}` does not have engine info", tag.value),
425 vec![self.source_range],
426 ))
427 })?;
428 Ok(info.clone())
429 }
430 _ => Err(KclError::new_internal(KclErrorDetails::new(
431 format!("Tag `{}` is bound to an unexpected type", tag.value),
432 vec![self.source_range],
433 ))),
434 }
435 }
436
437 pub(crate) fn get_tag_engine_info(
439 &self,
440 exec_state: &mut ExecState,
441 tag: &TagIdentifier,
442 ) -> Result<crate::execution::TagEngineInfo, KclError> {
443 if let Some(info) = tag.get_cur_info() {
444 return Ok(info.clone());
445 }
446
447 self.get_tag_info_from_memory(exec_state, tag)
448 }
449
450 fn get_tag_engine_info_check_surface(
452 &self,
453 exec_state: &mut ExecState,
454 tag: &TagIdentifier,
455 ) -> Result<crate::execution::TagEngineInfo, KclError> {
456 let info = tag.get_cur_info();
457 if let Some(info) = info
458 && info.surface.is_some()
459 {
460 return Ok(info.clone());
461 }
462
463 self.get_tag_info_from_memory(exec_state, tag).map_err(|err| {
464 if err.is_undefined_value() {
465 self.tag_requires_face_error(tag, info)
468 } else {
469 err
470 }
471 })
472 }
473
474 fn tag_requires_face_error(&self, tag: &TagIdentifier, info: Option<&crate::execution::TagEngineInfo>) -> KclError {
475 let what = if let Some(info) = info {
476 if info.path.is_some() {
477 match &info.geometry {
478 Geometry::Sketch(_) => "a sketch edge",
479 Geometry::Solid(_) => "a solid edge",
480 }
481 } else {
482 match &info.geometry {
483 Geometry::Sketch(_) => "sketch geometry",
484 Geometry::Solid(_) => "solid geometry",
485 }
486 }
487 } else {
488 "non-face geometry"
489 };
490
491 KclError::new_type(KclErrorDetails::new(
492 format!(
493 "Tag `{}` refers to {what}, but this operation requires a face tag",
494 tag.value
495 ),
496 vec![self.source_range],
497 ))
498 }
499
500 pub(crate) fn make_kcl_val_from_point(&self, p: [f64; 2], ty: NumericType) -> Result<KclValue, KclError> {
501 let meta = Metadata {
502 source_range: self.source_range,
503 };
504 let x = KclValue::Number {
505 value: p[0],
506 meta: vec![meta],
507 ty,
508 };
509 let y = KclValue::Number {
510 value: p[1],
511 meta: vec![meta],
512 ty,
513 };
514 let ty = RuntimeType::Primitive(PrimitiveType::Number(ty));
515
516 Ok(KclValue::HomArray { value: vec![x, y], ty })
517 }
518
519 pub(super) fn make_user_val_from_f64_with_type(&self, f: TyF64) -> KclValue {
520 KclValue::from_number_with_type(
521 f.n,
522 f.ty,
523 vec![Metadata {
524 source_range: self.source_range,
525 }],
526 )
527 }
528
529 pub(crate) async fn get_adjacent_face_to_tag(
531 &self,
532 exec_state: &mut ExecState,
533 tag: &TagIdentifier,
534 must_be_planar: bool,
535 ) -> Result<uuid::Uuid, KclError> {
536 if tag.value.is_empty() {
537 return Err(KclError::new_type(KclErrorDetails::new(
538 "Expected a non-empty tag for the face".to_string(),
539 vec![self.source_range],
540 )));
541 }
542
543 check_tag_not_ambiguous(tag, self)?;
545
546 let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?;
547
548 let surface = engine_info
549 .surface
550 .as_ref()
551 .ok_or_else(|| self.tag_requires_face_error(tag, Some(&engine_info)))?;
552
553 if let Some(face_from_surface) = match surface {
554 ExtrudeSurface::ExtrudePlane(extrude_plane) => {
555 if let Some(plane_tag) = &extrude_plane.tag {
556 if plane_tag.name == tag.value {
557 Some(Ok(extrude_plane.face_id))
558 } else {
559 None
560 }
561 } else {
562 None
563 }
564 }
565 ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::new_type(KclErrorDetails::new(
567 format!("Tag `{}` is a non-planar surface", tag.value),
568 vec![self.source_range],
569 )))),
570 ExtrudeSurface::ExtrudeArc(extrude_arc) => {
571 if let Some(arc_tag) = &extrude_arc.tag {
572 if arc_tag.name == tag.value {
573 Some(Ok(extrude_arc.face_id))
574 } else {
575 None
576 }
577 } else {
578 None
579 }
580 }
581 ExtrudeSurface::Chamfer(chamfer) => {
582 if let Some(chamfer_tag) = &chamfer.tag {
583 if chamfer_tag.name == tag.value {
584 Some(Ok(chamfer.face_id))
585 } else {
586 None
587 }
588 } else {
589 None
590 }
591 }
592 ExtrudeSurface::Fillet(_) if must_be_planar => Some(Err(KclError::new_type(KclErrorDetails::new(
594 format!("Tag `{}` is a non-planar surface", tag.value),
595 vec![self.source_range],
596 )))),
597 ExtrudeSurface::Fillet(fillet) => {
598 if let Some(fillet_tag) = &fillet.tag {
599 if fillet_tag.name == tag.value {
600 Some(Ok(fillet.face_id))
601 } else {
602 None
603 }
604 } else {
605 None
606 }
607 }
608 } {
609 return face_from_surface;
610 }
611
612 Err(KclError::new_type(KclErrorDetails::new(
614 format!("Expected a face with the tag `{}`", tag.value),
615 vec![self.source_range],
616 )))
617 }
618}
619
620pub trait FromKclValue<'a>: Sized {
622 fn from_kcl_val(arg: &'a KclValue) -> Option<Self>;
624}
625
626impl<'a> FromKclValue<'a> for TagNode {
627 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
628 arg.get_tag_declarator().ok()
629 }
630}
631
632impl<'a> FromKclValue<'a> for TagIdentifier {
633 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
634 arg.get_tag_identifier().ok()
635 }
636}
637
638impl<'a> FromKclValue<'a> for Vec<TagIdentifier> {
639 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
640 let tags = arg
641 .clone()
642 .into_array()
643 .iter()
644 .map(|v| v.get_tag_identifier().unwrap())
645 .collect();
646 Some(tags)
647 }
648}
649
650impl<'a> FromKclValue<'a> for Vec<KclValue> {
651 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
652 Some(arg.clone().into_array())
653 }
654}
655
656impl<'a> FromKclValue<'a> for Vec<Extrudable> {
657 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
658 let items = arg
659 .clone()
660 .into_array()
661 .iter()
662 .map(Extrudable::from_kcl_val)
663 .collect::<Option<Vec<_>>>()?;
664 Some(items)
665 }
666}
667
668impl<'a> FromKclValue<'a> for KclValue {
669 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
670 Some(arg.clone())
671 }
672}
673
674macro_rules! let_field_of {
675 ($obj:ident, $field:ident?) => {
677 let $field = $obj.get(stringify!($field)).and_then(FromKclValue::from_kcl_val);
678 };
679 ($obj:ident, $field:ident? $key:literal) => {
681 let $field = $obj.get($key).and_then(FromKclValue::from_kcl_val);
682 };
683 ($obj:ident, $field:ident $key:literal) => {
685 let $field = $obj.get($key).and_then(FromKclValue::from_kcl_val)?;
686 };
687 ($obj:ident, $field:ident $(, $annotation:ty)?) => {
689 let $field $(: $annotation)? = $obj.get(stringify!($field)).and_then(FromKclValue::from_kcl_val)?;
690 };
691}
692
693impl<'a> FromKclValue<'a> for crate::execution::Plane {
694 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
695 arg.as_plane().cloned()
696 }
697}
698
699impl<'a> FromKclValue<'a> for crate::execution::PlaneKind {
700 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
701 let plane_type = match arg.as_str()? {
702 "XY" | "xy" => Self::XY,
703 "XZ" | "xz" => Self::XZ,
704 "YZ" | "yz" => Self::YZ,
705 "Custom" => Self::Custom,
706 _ => return None,
707 };
708 Some(plane_type)
709 }
710}
711
712impl<'a> FromKclValue<'a> for BodyType {
713 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
714 let body_type = match arg.as_str()? {
715 "solid" => Self::Solid,
716 "surface" => Self::Surface,
717 _ => return None,
718 };
719 Some(body_type)
720 }
721}
722
723impl<'a> FromKclValue<'a> for CircularDirection {
724 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
725 let dir = match arg.as_str()? {
726 "ccw" => Self::Counterclockwise,
727 "cw" => Self::Clockwise,
728 _ => return None,
729 };
730 Some(dir)
731 }
732}
733
734impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::units::UnitLength {
735 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
736 let s = arg.as_str()?;
737 s.parse().ok()
738 }
739}
740
741impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::System {
742 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
743 let obj = arg.as_object()?;
744 let_field_of!(obj, forward);
745 let_field_of!(obj, up);
746 Some(Self { forward, up })
747 }
748}
749
750impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::AxisDirectionPair {
751 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
752 let obj = arg.as_object()?;
753 let_field_of!(obj, axis);
754 let_field_of!(obj, direction);
755 Some(Self { axis, direction })
756 }
757}
758
759impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::Axis {
760 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
761 let s = arg.as_str()?;
762 match s {
763 "y" => Some(Self::Y),
764 "z" => Some(Self::Z),
765 _ => None,
766 }
767 }
768}
769
770impl<'a> FromKclValue<'a> for PolygonType {
771 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
772 let s = arg.as_str()?;
773 match s {
774 "inscribed" => Some(Self::Inscribed),
775 _ => Some(Self::Circumscribed),
776 }
777 }
778}
779
780impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::Direction {
781 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
782 let s = arg.as_str()?;
783 match s {
784 "positive" => Some(Self::Positive),
785 "negative" => Some(Self::Negative),
786 _ => None,
787 }
788 }
789}
790
791impl<'a> FromKclValue<'a> for crate::execution::Geometry {
792 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
793 match arg {
794 KclValue::Sketch { value } => Some(Self::Sketch(*value.to_owned())),
795 KclValue::Solid { value } => Some(Self::Solid(*value.to_owned())),
796 _ => None,
797 }
798 }
799}
800
801impl<'a> FromKclValue<'a> for crate::execution::GeometryWithImportedGeometry {
802 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
803 match arg {
804 KclValue::Sketch { value } => Some(Self::Sketch(*value.to_owned())),
805 KclValue::Solid { value } => Some(Self::Solid(*value.to_owned())),
806 KclValue::ImportedGeometry(value) => Some(Self::ImportedGeometry(Box::new(value.clone()))),
807 _ => None,
808 }
809 }
810}
811
812impl<'a> FromKclValue<'a> for FaceTag {
813 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
814 let case1 = || match arg.as_str() {
815 Some("start" | "START") => Some(Self::StartOrEnd(super::sketch::StartOrEnd::Start)),
816 Some("end" | "END") => Some(Self::StartOrEnd(super::sketch::StartOrEnd::End)),
817 _ => None,
818 };
819 let case2 = || {
820 let tag = TagIdentifier::from_kcl_val(arg)?;
821 Some(Self::Tag(Box::new(tag)))
822 };
823 case1().or_else(case2)
824 }
825}
826
827impl<'a> FromKclValue<'a> for super::faces::FaceSpecifier {
828 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
829 FaceTag::from_kcl_val(arg)
830 .map(super::faces::FaceSpecifier::FaceTag)
831 .or_else(|| {
832 crate::execution::Segment::from_kcl_val(arg)
833 .map(Box::new)
834 .map(super::faces::FaceSpecifier::Segment)
835 })
836 }
837}
838
839impl<'a> FromKclValue<'a> for crate::execution::Segment {
840 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
841 match arg {
842 KclValue::Segment { value } => match &value.repr {
843 crate::execution::SegmentRepr::Unsolved { .. } => None,
844 crate::execution::SegmentRepr::Solved { segment, .. } => Some(segment.as_ref().to_owned()),
845 },
846 _ => None,
847 }
848 }
849}
850
851impl<'a> FromKclValue<'a> for super::sketch::TangentialArcData {
852 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
853 let obj = arg.as_object()?;
854 let_field_of!(obj, radius);
855 let_field_of!(obj, offset);
856 Some(Self::RadiusAndOffset { radius, offset })
857 }
858}
859
860impl<'a> FromKclValue<'a> for crate::execution::Point3d {
861 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
862 if let Some(obj) = arg.as_object() {
864 let_field_of!(obj, x, TyF64);
865 let_field_of!(obj, y, TyF64);
866 let_field_of!(obj, z, TyF64);
867 let (a, ty) = NumericType::combine_eq_array(&[x, y, z]);
869 return Some(Self {
870 x: a[0],
871 y: a[1],
872 z: a[2],
873 units: ty.as_length(),
874 });
875 }
876 let [x, y, z]: [TyF64; 3] = FromKclValue::from_kcl_val(arg)?;
878 let (a, ty) = NumericType::combine_eq_array(&[x, y, z]);
879 Some(Self {
880 x: a[0],
881 y: a[1],
882 z: a[2],
883 units: ty.as_length(),
884 })
885 }
886}
887
888impl<'a> FromKclValue<'a> for super::sketch::PlaneData {
889 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
890 if let KclValue::Plane { value } = arg {
892 return Some(Self::Plane(PlaneInfo {
893 origin: value.info.origin,
894 x_axis: value.info.x_axis,
895 y_axis: value.info.y_axis,
896 z_axis: value.info.z_axis,
897 }));
898 }
899 if let Some(s) = arg.as_str() {
901 return match s {
902 "XY" | "xy" => Some(Self::XY),
903 "-XY" | "-xy" => Some(Self::NegXY),
904 "XZ" | "xz" => Some(Self::XZ),
905 "-XZ" | "-xz" => Some(Self::NegXZ),
906 "YZ" | "yz" => Some(Self::YZ),
907 "-YZ" | "-yz" => Some(Self::NegYZ),
908 _ => None,
909 };
910 }
911 let obj = arg.as_object()?;
913 let_field_of!(obj, plane, &KclObjectFields);
914 let origin = plane.get("origin").and_then(FromKclValue::from_kcl_val)?;
915 let x_axis: crate::execution::Point3d = plane.get("xAxis").and_then(FromKclValue::from_kcl_val)?;
916 let y_axis = plane.get("yAxis").and_then(FromKclValue::from_kcl_val)?;
917 let z_axis = x_axis.axes_cross_product(&y_axis);
918 Some(Self::Plane(PlaneInfo {
919 origin,
920 x_axis,
921 y_axis,
922 z_axis,
923 }))
924 }
925}
926
927impl<'a> FromKclValue<'a> for crate::execution::ExtrudePlane {
928 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
929 let obj = arg.as_object()?;
930 let_field_of!(obj, face_id "faceId");
931 let tag = FromKclValue::from_kcl_val(obj.get("tag")?);
932 let_field_of!(obj, geo_meta "geoMeta");
933 Some(Self { face_id, tag, geo_meta })
934 }
935}
936
937impl<'a> FromKclValue<'a> for crate::execution::ExtrudeArc {
938 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
939 let obj = arg.as_object()?;
940 let_field_of!(obj, face_id "faceId");
941 let tag = FromKclValue::from_kcl_val(obj.get("tag")?);
942 let_field_of!(obj, geo_meta "geoMeta");
943 Some(Self { face_id, tag, geo_meta })
944 }
945}
946
947impl<'a> FromKclValue<'a> for crate::execution::GeoMeta {
948 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
949 let obj = arg.as_object()?;
950 let_field_of!(obj, id);
951 let_field_of!(obj, source_range "sourceRange");
952 Some(Self {
953 id,
954 metadata: Metadata { source_range },
955 })
956 }
957}
958
959impl<'a> FromKclValue<'a> for crate::execution::ChamferSurface {
960 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
961 let obj = arg.as_object()?;
962 let_field_of!(obj, face_id "faceId");
963 let tag = FromKclValue::from_kcl_val(obj.get("tag")?);
964 let_field_of!(obj, geo_meta "geoMeta");
965 Some(Self { face_id, tag, geo_meta })
966 }
967}
968
969impl<'a> FromKclValue<'a> for crate::execution::FilletSurface {
970 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
971 let obj = arg.as_object()?;
972 let_field_of!(obj, face_id "faceId");
973 let tag = FromKclValue::from_kcl_val(obj.get("tag")?);
974 let_field_of!(obj, geo_meta "geoMeta");
975 Some(Self { face_id, tag, geo_meta })
976 }
977}
978
979impl<'a> FromKclValue<'a> for ExtrudeSurface {
980 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
981 let case1 = crate::execution::ExtrudePlane::from_kcl_val;
982 let case2 = crate::execution::ExtrudeArc::from_kcl_val;
983 let case3 = crate::execution::ChamferSurface::from_kcl_val;
984 let case4 = crate::execution::FilletSurface::from_kcl_val;
985 case1(arg)
986 .map(Self::ExtrudePlane)
987 .or_else(|| case2(arg).map(Self::ExtrudeArc))
988 .or_else(|| case3(arg).map(Self::Chamfer))
989 .or_else(|| case4(arg).map(Self::Fillet))
990 }
991}
992
993impl<'a> FromKclValue<'a> for crate::execution::EdgeCut {
994 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
995 let obj = arg.as_object()?;
996 let_field_of!(obj, typ "type");
997 let tag = Box::new(obj.get("tag").and_then(FromKclValue::from_kcl_val));
998 let_field_of!(obj, edge_id "edgeId");
999 let_field_of!(obj, id);
1000 match typ {
1001 "fillet" => {
1002 let_field_of!(obj, radius);
1003 Some(Self::Fillet {
1004 edge_id,
1005 tag,
1006 id,
1007 radius,
1008 })
1009 }
1010 "chamfer" => {
1011 let_field_of!(obj, length);
1012 Some(Self::Chamfer {
1013 id,
1014 length,
1015 edge_id,
1016 tag,
1017 })
1018 }
1019 _ => None,
1020 }
1021 }
1022}
1023
1024macro_rules! impl_from_kcl_for_vec {
1025 ($typ:path) => {
1026 impl<'a> FromKclValue<'a> for Vec<$typ> {
1027 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1028 arg.clone()
1029 .into_array()
1030 .iter()
1031 .map(|value| FromKclValue::from_kcl_val(value))
1032 .collect::<Option<_>>()
1033 }
1034 }
1035 };
1036}
1037
1038impl_from_kcl_for_vec!(FaceTag);
1039impl_from_kcl_for_vec!(crate::execution::EdgeCut);
1040impl_from_kcl_for_vec!(crate::execution::Metadata);
1041impl_from_kcl_for_vec!(super::fillet::EdgeReference);
1042impl_from_kcl_for_vec!(ExtrudeSurface);
1043impl_from_kcl_for_vec!(Segment);
1044impl_from_kcl_for_vec!(TyF64);
1045impl_from_kcl_for_vec!(Solid);
1046impl_from_kcl_for_vec!(Sketch);
1047impl_from_kcl_for_vec!(crate::execution::GdtAnnotation);
1048impl_from_kcl_for_vec!(crate::execution::GeometryWithImportedGeometry);
1049impl_from_kcl_for_vec!(crate::execution::BoundedEdge);
1050impl_from_kcl_for_vec!(String);
1051
1052impl<'a> FromKclValue<'a> for SourceRange {
1053 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1054 let value = match arg {
1055 KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => value,
1056 _ => {
1057 return None;
1058 }
1059 };
1060 let [v0, v1, v2] = value.as_slice() else {
1061 return None;
1062 };
1063 Some(SourceRange::new(
1064 v0.as_usize()?,
1065 v1.as_usize()?,
1066 ModuleId::from_usize(v2.as_usize()?),
1067 ))
1068 }
1069}
1070
1071impl<'a> FromKclValue<'a> for crate::execution::Metadata {
1072 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1073 FromKclValue::from_kcl_val(arg).map(|sr| Self { source_range: sr })
1074 }
1075}
1076
1077impl<'a> FromKclValue<'a> for crate::execution::Solid {
1078 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1079 arg.as_solid().cloned()
1080 }
1081}
1082
1083impl<'a> FromKclValue<'a> for crate::execution::GdtAnnotation {
1084 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1085 let KclValue::GdtAnnotation { value } = arg else {
1086 return None;
1087 };
1088 Some(value.as_ref().to_owned())
1089 }
1090}
1091
1092impl<'a> FromKclValue<'a> for crate::execution::SolidOrSketchOrImportedGeometry {
1093 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1094 match arg {
1095 KclValue::Solid { value } => Some(Self::SolidSet(vec![(**value).clone()])),
1096 KclValue::Sketch { value } => Some(Self::SketchSet(vec![(**value).clone()])),
1097 KclValue::Helix { value } => Some(Self::HelixSet(vec![(**value).clone()])),
1098 KclValue::HomArray { value, .. } => {
1099 let mut solids = vec![];
1100 let mut sketches = vec![];
1101 let mut helices = vec![];
1102 for item in value {
1103 match item {
1104 KclValue::Solid { value } => solids.push((**value).clone()),
1105 KclValue::Sketch { value } => sketches.push((**value).clone()),
1106 KclValue::Helix { value } => helices.push((**value).clone()),
1107 _ => return None,
1108 }
1109 }
1110 if !solids.is_empty() {
1111 Some(Self::SolidSet(solids))
1112 } else if !helices.is_empty() {
1113 Some(Self::HelixSet(helices))
1114 } else {
1115 Some(Self::SketchSet(sketches))
1116 }
1117 }
1118 KclValue::ImportedGeometry(value) => Some(Self::ImportedGeometry(Box::new(value.clone()))),
1119 _ => None,
1120 }
1121 }
1122}
1123
1124impl<'a> FromKclValue<'a> for crate::execution::HideableGeometry {
1125 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1126 match arg {
1127 KclValue::Solid { value } => Some(Self::SolidSet(vec![(**value).clone()])),
1128 KclValue::Plane { value } => Some(Self::PlaneSet(vec![(**value).clone()])),
1129 KclValue::Sketch { value } => Some(Self::SketchSet(vec![(**value).clone()])),
1130 KclValue::Helix { value } => Some(Self::HelixSet(vec![(**value).clone()])),
1131 KclValue::GdtAnnotation { value } => Some(Self::GdtAnnotationSet(vec![(**value).clone()])),
1132 KclValue::HomArray { value, .. } => {
1133 let mut solids = vec![];
1134 let mut planes = vec![];
1135 let mut sketches = vec![];
1136 let mut helices = vec![];
1137 let mut annotations = vec![];
1138 for item in value {
1139 match item {
1140 KclValue::Solid { value } => solids.push((**value).clone()),
1141 KclValue::Plane { value } => planes.push((**value).clone()),
1142 KclValue::Sketch { value } => sketches.push((**value).clone()),
1143 KclValue::Helix { value } => helices.push((**value).clone()),
1144 KclValue::GdtAnnotation { value } => annotations.push((**value).clone()),
1145 _ => return None,
1146 }
1147 }
1148 if !solids.is_empty() {
1149 Some(Self::SolidSet(solids))
1150 } else if !planes.is_empty() {
1151 Some(Self::PlaneSet(planes))
1152 } else if !sketches.is_empty() {
1153 Some(Self::SketchSet(sketches))
1154 } else if !helices.is_empty() {
1155 Some(Self::HelixSet(helices))
1156 } else {
1157 Some(Self::GdtAnnotationSet(annotations))
1158 }
1159 }
1160 KclValue::ImportedGeometry(value) => Some(Self::ImportedGeometry(Box::new(value.clone()))),
1161 _ => None,
1162 }
1163 }
1164}
1165
1166impl<'a> FromKclValue<'a> for crate::execution::SolidOrImportedGeometry {
1167 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1168 match arg {
1169 KclValue::Solid { value } => Some(Self::SolidSet(vec![(**value).clone()])),
1170 KclValue::HomArray { value, .. } => {
1171 let mut solids = vec![];
1172 for item in value {
1173 match item {
1174 KclValue::Solid { value } => solids.push((**value).clone()),
1175 _ => return None,
1176 }
1177 }
1178 Some(Self::SolidSet(solids))
1179 }
1180 KclValue::ImportedGeometry(value) => Some(Self::ImportedGeometry(Box::new(value.clone()))),
1181 _ => None,
1182 }
1183 }
1184}
1185
1186impl<'a> FromKclValue<'a> for super::sketch::SketchData {
1187 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1188 let case1 = crate::execution::Plane::from_kcl_val;
1190 let case2 = super::sketch::PlaneData::from_kcl_val;
1191 let case3 = crate::execution::Solid::from_kcl_val;
1192 let case4 = <Vec<Solid>>::from_kcl_val;
1193 case1(arg)
1194 .map(Box::new)
1195 .map(Self::Plane)
1196 .or_else(|| case2(arg).map(Self::PlaneOrientation))
1197 .or_else(|| case3(arg).map(Box::new).map(Self::Solid))
1198 .or_else(|| case4(arg).map(|v| Box::new(v[0].clone())).map(Self::Solid))
1199 }
1200}
1201
1202impl<'a> FromKclValue<'a> for super::fillet::EdgeReference {
1203 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1204 let id = arg.as_uuid().map(Self::Uuid);
1205 let tag = || TagIdentifier::from_kcl_val(arg).map(Box::new).map(Self::Tag);
1206 id.or_else(tag)
1207 }
1208}
1209
1210impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis2dOrEdgeReference {
1211 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1212 let case1 = |arg: &KclValue| {
1213 let obj = arg.as_object()?;
1214 let_field_of!(obj, direction);
1215 let_field_of!(obj, origin);
1216 let origin: [TyF64; 2] = origin;
1217 if !is_lengths(&origin) {
1218 return None;
1219 }
1220 let direction: [TyF64; 2] = direction;
1221 if !is_lengths(&direction) {
1222 return None;
1223 }
1224 Some(Self::Axis { direction, origin })
1225 };
1226 let case2 = super::fillet::EdgeReference::from_kcl_val;
1227 let case3 = Segment::from_kcl_val;
1228 case1(arg)
1229 .or_else(|| case2(arg).map(Self::Edge))
1230 .or_else(|| case3(arg).and_then(|seg| Self::from_segment(&seg).ok()))
1231 }
1232}
1233
1234impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis3dOrEdgeReference {
1235 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1236 let case1 = |arg: &KclValue| {
1237 let obj = arg.as_object()?;
1238 let_field_of!(obj, direction);
1239 let direction: [TyF64; 3] = direction;
1240 if !is_lengths(&direction) {
1241 return None;
1242 }
1243 let_field_of!(obj, origin);
1244 let origin: [TyF64; 3] = origin;
1245 if !is_lengths(&origin) {
1246 return None;
1247 }
1248 Some(Self::Axis { direction, origin })
1249 };
1250 let case2 = super::fillet::EdgeReference::from_kcl_val;
1251 let case3 = Segment::from_kcl_val;
1252 case1(arg)
1253 .or_else(|| case2(arg).map(Self::Edge))
1254 .or_else(|| case3(arg).and_then(|seg| Self::from_segment(&seg).ok()))
1255 }
1256}
1257
1258impl<'a> FromKclValue<'a> for super::axis_or_reference::Point3dOrEdgeReference {
1259 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1260 let case1 = <[TyF64; 3]>::from_kcl_val;
1261 let case2 = super::fillet::EdgeReference::from_kcl_val;
1262 let case3 = Segment::from_kcl_val;
1263 case1(arg)
1264 .map(Self::Point)
1265 .or_else(|| case2(arg).map(Self::Edge))
1266 .or_else(|| case3(arg).and_then(|seg| Self::from_segment(&seg).ok()))
1267 }
1268}
1269
1270impl<'a> FromKclValue<'a> for super::axis_or_reference::MirrorAcross3d {
1271 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1272 let case1 = crate::execution::Plane::from_kcl_val;
1273 let case2 = |arg: &KclValue| {
1274 let obj = arg.as_object()?;
1275 let_field_of!(obj, direction);
1276 let direction: [TyF64; 3] = direction;
1277 if !is_lengths(&direction) {
1278 return None;
1279 }
1280 let_field_of!(obj, origin);
1281 let origin: [TyF64; 3] = origin;
1282 if !is_lengths(&origin) {
1283 return None;
1284 }
1285 Some(Self::Axis {
1286 direction: Box::new(direction),
1287 origin: Box::new(origin),
1288 })
1289 };
1290 let case3 = super::fillet::EdgeReference::from_kcl_val;
1291 let case4 = Segment::from_kcl_val;
1292 case1(arg)
1293 .map(|p| Self::Plane(Box::new(p)))
1294 .or_else(|| case2(arg))
1295 .or_else(|| case3(arg).map(|e| Self::Edge(Box::new(e))))
1296 .or_else(|| case4(arg).and_then(|seg| Self::from_segment(&seg).ok()))
1297 }
1298}
1299
1300impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis2dOrPoint2d {
1301 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1302 let case1 = |arg: &KclValue| {
1303 let obj = arg.as_object()?;
1304 let_field_of!(obj, direction);
1305 let_field_of!(obj, origin);
1306 Some(Self::Axis { direction, origin })
1307 };
1308 let case2 = <[TyF64; 2]>::from_kcl_val;
1309 case1(arg).or_else(|| case2(arg).map(Self::Point))
1310 }
1311}
1312
1313impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis3dOrPoint3d {
1314 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1315 let case1 = |arg: &KclValue| {
1316 let obj = arg.as_object()?;
1317 let_field_of!(obj, direction);
1318 let_field_of!(obj, origin);
1319 Some(Self::Axis { direction, origin })
1320 };
1321 let case2 = <[TyF64; 3]>::from_kcl_val;
1322 case1(arg).or_else(|| case2(arg).map(Self::Point))
1323 }
1324}
1325
1326impl<'a> FromKclValue<'a> for super::axis_or_reference::Point3dAxis3dOrGeometryReference {
1327 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1328 let case1 = |arg: &KclValue| {
1329 let obj = arg.as_object()?;
1330 let_field_of!(obj, direction);
1331 let direction: [TyF64; 3] = direction;
1332 if !is_lengths(&direction) {
1333 return None;
1334 }
1335 let_field_of!(obj, origin);
1336 let origin: [TyF64; 3] = origin;
1337 if !is_lengths(&origin) {
1338 return None;
1339 }
1340 Some(Self::Axis { direction, origin })
1341 };
1342 let case2 = |arg: &KclValue| {
1343 let point: [TyF64; 3] = FromKclValue::from_kcl_val(arg)?;
1344 if !is_lengths(&point) {
1345 return None;
1346 }
1347 Some(point)
1348 };
1349 let case3 = super::fillet::EdgeReference::from_kcl_val;
1350 let case4 = FaceTag::from_kcl_val;
1351 let case5 = Box::<Solid>::from_kcl_val;
1352 let case6 = TagIdentifier::from_kcl_val;
1353 let case7 = Box::<Plane>::from_kcl_val;
1354 let case8 = Box::<Sketch>::from_kcl_val;
1355
1356 case1(arg)
1357 .or_else(|| case2(arg).map(Self::Point))
1358 .or_else(|| case3(arg).map(Self::Edge))
1359 .or_else(|| case4(arg).map(Self::Face))
1360 .or_else(|| case5(arg).map(Self::Solid))
1361 .or_else(|| case6(arg).map(Self::TaggedEdgeOrFace))
1362 .or_else(|| case7(arg).map(Self::Plane))
1363 .or_else(|| case8(arg).map(Self::Sketch))
1364 }
1365}
1366
1367impl<'a> FromKclValue<'a> for Box<Face> {
1368 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1369 let KclValue::Face { value } = arg else {
1370 return None;
1371 };
1372 Some(value.to_owned())
1373 }
1374}
1375
1376impl<'a> FromKclValue<'a> for Extrudable {
1377 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1378 let case1 = Box::<Sketch>::from_kcl_val;
1379 let case2 = FaceTag::from_kcl_val;
1380 let case3 = Box::<Face>::from_kcl_val;
1381 let case4 = Uuid::from_kcl_val;
1382 let case5 = Box::<TagIdentifier>::from_kcl_val;
1383 case1(arg)
1384 .map(Self::Sketch)
1385 .or_else(|| case2(arg).map(Self::FaceTag))
1386 .or_else(|| case3(arg).map(Self::Face))
1387 .or_else(|| case4(arg).map(Self::Edge))
1388 .or_else(|| case5(arg).map(Self::EdgeTag))
1389 }
1390}
1391
1392impl<'a> FromKclValue<'a> for i64 {
1393 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1394 match arg {
1395 KclValue::Number { value, .. } => crate::try_f64_to_i64(*value),
1396 _ => None,
1397 }
1398 }
1399}
1400
1401impl<'a> FromKclValue<'a> for &'a str {
1402 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1403 let KclValue::String { value, meta: _ } = arg else {
1404 return None;
1405 };
1406 Some(value)
1407 }
1408}
1409
1410impl<'a> FromKclValue<'a> for &'a KclObjectFields {
1411 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1412 let KclValue::Object { value, .. } = arg else {
1413 return None;
1414 };
1415 Some(value)
1416 }
1417}
1418
1419impl<'a> FromKclValue<'a> for uuid::Uuid {
1420 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1421 let KclValue::Uuid { value, meta: _ } = arg else {
1422 return None;
1423 };
1424 Some(*value)
1425 }
1426}
1427
1428impl<'a> FromKclValue<'a> for u32 {
1429 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1430 match arg {
1431 KclValue::Number { value, .. } => crate::try_f64_to_u32(*value),
1432 _ => None,
1433 }
1434 }
1435}
1436
1437impl<'a> FromKclValue<'a> for NonZeroU32 {
1438 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1439 u32::from_kcl_val(arg).and_then(|x| x.try_into().ok())
1440 }
1441}
1442
1443impl<'a> FromKclValue<'a> for u64 {
1444 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1445 match arg {
1446 KclValue::Number { value, .. } => crate::try_f64_to_u64(*value),
1447 _ => None,
1448 }
1449 }
1450}
1451
1452impl<'a> FromKclValue<'a> for TyF64 {
1453 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1454 match arg {
1455 KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, *ty)),
1456 _ => None,
1457 }
1458 }
1459}
1460
1461impl<'a> FromKclValue<'a> for crate::execution::Orientation {
1465 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1466 let KclValue::Enum { value } = arg else {
1467 return None;
1468 };
1469 Self::from_kcl_variant(value.variant())
1470 }
1471}
1472
1473impl<'a> FromKclValue<'a> for crate::execution::Visibility {
1474 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1475 let KclValue::Enum { value } = arg else {
1476 return None;
1477 };
1478 Self::from_kcl_variant(value.variant())
1479 }
1480}
1481
1482impl<'a> FromKclValue<'a> for crate::execution::Projection {
1483 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1484 let KclValue::Enum { value } = arg else {
1485 return None;
1486 };
1487 Self::from_kcl_variant(value.variant())
1488 }
1489}
1490
1491impl<'a> FromKclValue<'a> for crate::execution::CameraView {
1492 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1493 let KclValue::CameraView { value } = arg else {
1494 return None;
1495 };
1496 Some((**value).clone())
1497 }
1498}
1499
1500impl<'a> FromKclValue<'a> for [TyF64; 2] {
1501 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1502 match arg {
1503 KclValue::Tuple { value, meta: _ } | KclValue::HomArray { value, .. } => {
1504 let [v0, v1] = value.as_slice() else {
1505 return None;
1506 };
1507 let array = [v0.as_ty_f64()?, v1.as_ty_f64()?];
1508 Some(array)
1509 }
1510 _ => None,
1511 }
1512 }
1513}
1514
1515impl<'a> FromKclValue<'a> for [TyF64; 3] {
1516 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1517 match arg {
1518 KclValue::Tuple { value, meta: _ } | KclValue::HomArray { value, .. } => {
1519 let [v0, v1, v2] = value.as_slice() else {
1520 return None;
1521 };
1522 let array = [v0.as_ty_f64()?, v1.as_ty_f64()?, v2.as_ty_f64()?];
1523 Some(array)
1524 }
1525 _ => None,
1526 }
1527 }
1528}
1529
1530impl<'a> FromKclValue<'a> for [TyF64; 6] {
1531 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1532 match arg {
1533 KclValue::Tuple { value, meta: _ } | KclValue::HomArray { value, .. } => {
1534 let [v0, v1, v2, v3, v4, v5] = value.as_slice() else {
1535 return None;
1536 };
1537 let array = [
1538 v0.as_ty_f64()?,
1539 v1.as_ty_f64()?,
1540 v2.as_ty_f64()?,
1541 v3.as_ty_f64()?,
1542 v4.as_ty_f64()?,
1543 v5.as_ty_f64()?,
1544 ];
1545 Some(array)
1546 }
1547 _ => None,
1548 }
1549 }
1550}
1551
1552impl<'a> FromKclValue<'a> for Sketch {
1553 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1554 let KclValue::Sketch { value } = arg else {
1555 return None;
1556 };
1557 Some(value.as_ref().to_owned())
1558 }
1559}
1560
1561impl<'a> FromKclValue<'a> for Helix {
1562 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1563 let KclValue::Helix { value } = arg else {
1564 return None;
1565 };
1566 Some(value.as_ref().to_owned())
1567 }
1568}
1569
1570impl<'a> FromKclValue<'a> for SweepPath {
1571 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1572 let case1 = Sketch::from_kcl_val;
1573 let case2 = <Vec<Sketch>>::from_kcl_val;
1574 let case3 = Helix::from_kcl_val;
1575 let case4 = <Vec<Segment>>::from_kcl_val;
1576 case1(arg)
1577 .map(Self::Sketch)
1578 .or_else(|| case2(arg).map(|arg0: Vec<Sketch>| Self::Sketch(arg0[0].clone())))
1579 .or_else(|| case3(arg).map(|arg0: Helix| Self::Helix(Box::new(arg0))))
1580 .or_else(|| case4(arg).map(Self::Segments))
1581 }
1582}
1583impl<'a> FromKclValue<'a> for String {
1584 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1585 let KclValue::String { value, meta: _ } = arg else {
1586 return None;
1587 };
1588 Some(value.to_owned())
1589 }
1590}
1591impl<'a> FromKclValue<'a> for crate::parsing::ast::types::KclNone {
1592 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1593 let KclValue::KclNone { value, meta: _ } = arg else {
1594 return None;
1595 };
1596 Some(value.to_owned())
1597 }
1598}
1599impl<'a> FromKclValue<'a> for bool {
1600 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1601 let KclValue::Bool { value, meta: _ } = arg else {
1602 return None;
1603 };
1604 Some(*value)
1605 }
1606}
1607
1608impl<'a> FromKclValue<'a> for Box<Solid> {
1609 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1610 let KclValue::Solid { value } = arg else {
1611 return None;
1612 };
1613 Some(value.to_owned())
1614 }
1615}
1616
1617impl<'a> FromKclValue<'a> for BoundedEdge {
1618 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1619 let KclValue::BoundedEdge { value, .. } = arg else {
1620 return None;
1621 };
1622 Some(value.to_owned())
1623 }
1624}
1625
1626impl<'a> FromKclValue<'a> for Box<Plane> {
1627 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1628 let KclValue::Plane { value } = arg else {
1629 return None;
1630 };
1631 Some(value.to_owned())
1632 }
1633}
1634
1635impl<'a> FromKclValue<'a> for Box<Sketch> {
1636 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1637 let KclValue::Sketch { value } = arg else {
1638 return None;
1639 };
1640 Some(value.to_owned())
1641 }
1642}
1643
1644impl<'a> FromKclValue<'a> for Box<TagIdentifier> {
1645 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1646 let KclValue::TagIdentifier(value) = arg else {
1647 return None;
1648 };
1649 Some(value.to_owned())
1650 }
1651}
1652
1653impl<'a> FromKclValue<'a> for FunctionSource {
1654 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1655 arg.as_function().cloned()
1656 }
1657}
1658
1659impl<'a> FromKclValue<'a> for HasAppearance {
1660 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1661 match arg {
1662 KclValue::Solid { value } => Some(Self::SolidSet(vec![(**value).clone()])),
1663 KclValue::Plane { value } => Some(Self::Plane(value.to_owned())),
1664 KclValue::HomArray { value, .. } => {
1665 let mut solids = vec![];
1666 for item in value {
1667 match item {
1668 KclValue::Solid { value } => solids.push((**value).clone()),
1669 _ => return None,
1670 }
1671 }
1672 Some(Self::SolidSet(solids))
1673 }
1674 KclValue::ImportedGeometry(value) => Some(Self::ImportedGeometry(Box::new(value.clone()))),
1675 _ => None,
1676 }
1677 }
1678}
1679
1680impl<'a> FromKclValue<'a> for SketchOrSurface {
1681 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1682 match arg {
1683 KclValue::Sketch { value: sg } => Some(Self::Sketch(sg.to_owned())),
1684 KclValue::Plane { value } => Some(Self::SketchSurface(SketchSurface::Plane(value.clone()))),
1685 KclValue::Face { value } => Some(Self::SketchSurface(SketchSurface::Face(value.clone()))),
1686 _ => None,
1687 }
1688 }
1689}
1690impl<'a> FromKclValue<'a> for SketchSurface {
1691 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1692 match arg {
1693 KclValue::Plane { value } => Some(Self::Plane(value.clone())),
1694 KclValue::Face { value } => Some(Self::Face(value.clone())),
1695 _ => None,
1696 }
1697 }
1698}
1699
1700impl From<Args> for Metadata {
1701 fn from(value: Args) -> Self {
1702 Self {
1703 source_range: value.source_range,
1704 }
1705 }
1706}
1707
1708impl From<Args> for Vec<Metadata> {
1709 fn from(value: Args) -> Self {
1710 vec![Metadata {
1711 source_range: value.source_range,
1712 }]
1713 }
1714}