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