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