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