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