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