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