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