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