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