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