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