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