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