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