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.stack().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 .stack()
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::MixedArray {
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::MixedArray {
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_sketches(&self) -> Result<(SketchSet, Sketch), KclError> {
448 FromArgs::from_args(self, 0)
449 }
450
451 pub(crate) fn get_sketch(&self) -> Result<Sketch, KclError> {
452 FromArgs::from_args(self, 0)
453 }
454
455 pub(crate) fn get_data<'a, T>(&'a self) -> Result<T, KclError>
456 where
457 T: FromArgs<'a> + serde::de::DeserializeOwned,
458 {
459 FromArgs::from_args(self, 0)
460 }
461
462 pub(crate) fn get_import_data(&self) -> Result<(String, Option<crate::std::import::ImportFormat>), KclError> {
463 FromArgs::from_args(self, 0)
464 }
465
466 pub(crate) fn get_data_and_optional_tag<'a, T>(&'a self) -> Result<(T, Option<FaceTag>), KclError>
467 where
468 T: serde::de::DeserializeOwned + FromKclValue<'a> + Sized,
469 {
470 FromArgs::from_args(self, 0)
471 }
472
473 pub(crate) fn get_data_and_sketch<'a, T>(&'a self) -> Result<(T, Sketch), KclError>
474 where
475 T: serde::de::DeserializeOwned + FromArgs<'a>,
476 {
477 FromArgs::from_args(self, 0)
478 }
479
480 pub(crate) fn get_data_and_sketch_set<'a, T>(&'a self) -> Result<(T, SketchSet), KclError>
481 where
482 T: serde::de::DeserializeOwned + FromArgs<'a>,
483 {
484 FromArgs::from_args(self, 0)
485 }
486
487 pub(crate) fn get_data_and_sketch_and_tag<'a, T>(&'a self) -> Result<(T, Sketch, Option<TagNode>), KclError>
488 where
489 T: serde::de::DeserializeOwned + FromKclValue<'a> + Sized,
490 {
491 FromArgs::from_args(self, 0)
492 }
493
494 pub(crate) fn get_data_and_sketch_surface<'a, T>(&'a self) -> Result<(T, SketchSurface, Option<TagNode>), KclError>
495 where
496 T: serde::de::DeserializeOwned + FromKclValue<'a> + Sized,
497 {
498 FromArgs::from_args(self, 0)
499 }
500
501 pub(crate) fn get_data_and_solid<'a, T>(&'a self) -> Result<(T, Box<Solid>), KclError>
502 where
503 T: serde::de::DeserializeOwned + FromKclValue<'a> + Sized,
504 {
505 FromArgs::from_args(self, 0)
506 }
507
508 pub(crate) fn get_tag_to_number_sketch(&self) -> Result<(TagIdentifier, f64, Sketch), KclError> {
509 FromArgs::from_args(self, 0)
510 }
511
512 pub(crate) async fn get_adjacent_face_to_tag(
513 &self,
514 exec_state: &mut ExecState,
515 tag: &TagIdentifier,
516 must_be_planar: bool,
517 ) -> Result<uuid::Uuid, KclError> {
518 if tag.value.is_empty() {
519 return Err(KclError::Type(KclErrorDetails {
520 message: "Expected a non-empty tag for the face".to_string(),
521 source_ranges: vec![self.source_range],
522 }));
523 }
524
525 let engine_info = self.get_tag_engine_info_check_surface(exec_state, tag)?;
526
527 let surface = engine_info.surface.as_ref().ok_or_else(|| {
528 KclError::Type(KclErrorDetails {
529 message: format!("Tag `{}` does not have a surface", tag.value),
530 source_ranges: vec![self.source_range],
531 })
532 })?;
533
534 if let Some(face_from_surface) = match surface {
535 ExtrudeSurface::ExtrudePlane(extrude_plane) => {
536 if let Some(plane_tag) = &extrude_plane.tag {
537 if plane_tag.name == tag.value {
538 Some(Ok(extrude_plane.face_id))
539 } else {
540 None
541 }
542 } else {
543 None
544 }
545 }
546 ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails {
548 message: format!("Tag `{}` is a non-planar surface", tag.value),
549 source_ranges: vec![self.source_range],
550 }))),
551 ExtrudeSurface::ExtrudeArc(extrude_arc) => {
552 if let Some(arc_tag) = &extrude_arc.tag {
553 if arc_tag.name == tag.value {
554 Some(Ok(extrude_arc.face_id))
555 } else {
556 None
557 }
558 } else {
559 None
560 }
561 }
562 ExtrudeSurface::Chamfer(chamfer) => {
563 if let Some(chamfer_tag) = &chamfer.tag {
564 if chamfer_tag.name == tag.value {
565 Some(Ok(chamfer.face_id))
566 } else {
567 None
568 }
569 } else {
570 None
571 }
572 }
573 ExtrudeSurface::Fillet(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails {
575 message: format!("Tag `{}` is a non-planar surface", tag.value),
576 source_ranges: vec![self.source_range],
577 }))),
578 ExtrudeSurface::Fillet(fillet) => {
579 if let Some(fillet_tag) = &fillet.tag {
580 if fillet_tag.name == tag.value {
581 Some(Ok(fillet.face_id))
582 } else {
583 None
584 }
585 } else {
586 None
587 }
588 }
589 } {
590 return face_from_surface;
591 }
592
593 Err(KclError::Type(KclErrorDetails {
595 message: format!("Expected a face with the tag `{}`", tag.value),
596 source_ranges: vec![self.source_range],
597 }))
598 }
599
600 pub(crate) fn get_polygon_args(
601 &self,
602 ) -> Result<
603 (
604 crate::std::shapes::PolygonData,
605 crate::std::shapes::SketchOrSurface,
606 Option<TagNode>,
607 ),
608 KclError,
609 > {
610 FromArgs::from_args(self, 0)
611 }
612}
613
614pub trait FromArgs<'a>: Sized {
616 fn from_args(args: &'a Args, index: usize) -> Result<Self, KclError>;
618}
619
620pub trait FromKclValue<'a>: Sized {
622 fn from_kcl_val(arg: &'a KclValue) -> Option<Self>;
624}
625
626impl<'a> FromArgs<'a> for Vec<KclValue> {
627 fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
628 let Some(arg) = args.args.get(i) else {
629 return Err(KclError::Semantic(KclErrorDetails {
630 message: format!("Expected an argument at index {i}"),
631 source_ranges: vec![args.source_range],
632 }));
633 };
634 let KclValue::MixedArray { value: array, meta: _ } = &arg.value else {
635 let message = format!("Expected an array but found {}", arg.value.human_friendly_type());
636 return Err(KclError::Type(KclErrorDetails {
637 source_ranges: arg.source_ranges(),
638 message,
639 }));
640 };
641 Ok(array.to_owned())
642 }
643}
644
645impl<'a, T> FromArgs<'a> for T
646where
647 T: FromKclValue<'a> + Sized,
648{
649 fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
650 let Some(arg) = args.args.get(i) else {
651 return Err(KclError::Semantic(KclErrorDetails {
652 message: format!("Expected an argument at index {i}"),
653 source_ranges: vec![args.source_range],
654 }));
655 };
656 let Some(val) = T::from_kcl_val(&arg.value) else {
657 return Err(KclError::Semantic(KclErrorDetails {
658 message: format!(
659 "Argument at index {i} was supposed to be type {} but found {}",
660 type_name::<T>(),
661 arg.value.human_friendly_type(),
662 ),
663 source_ranges: arg.source_ranges(),
664 }));
665 };
666 Ok(val)
667 }
668}
669
670impl<'a, T> FromArgs<'a> for Option<T>
671where
672 T: FromKclValue<'a> + Sized,
673{
674 fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
675 let Some(arg) = args.args.get(i) else { return Ok(None) };
676 if crate::parsing::ast::types::KclNone::from_kcl_val(&arg.value).is_some() {
677 return Ok(None);
678 }
679 let Some(val) = T::from_kcl_val(&arg.value) else {
680 return Err(KclError::Semantic(KclErrorDetails {
681 message: format!(
682 "Argument at index {i} was supposed to be type Option<{}> but found {}",
683 type_name::<T>(),
684 arg.value.human_friendly_type()
685 ),
686 source_ranges: arg.source_ranges(),
687 }));
688 };
689 Ok(Some(val))
690 }
691}
692
693impl<'a, A, B> FromArgs<'a> for (A, B)
694where
695 A: FromArgs<'a>,
696 B: FromArgs<'a>,
697{
698 fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
699 let a = A::from_args(args, i)?;
700 let b = B::from_args(args, i + 1)?;
701 Ok((a, b))
702 }
703}
704
705impl<'a, A, B, C> FromArgs<'a> for (A, B, C)
706where
707 A: FromArgs<'a>,
708 B: FromArgs<'a>,
709 C: 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 let c = C::from_args(args, i + 2)?;
715 Ok((a, b, c))
716 }
717}
718impl<'a, A, B, C, D> FromArgs<'a> for (A, B, C, D)
719where
720 A: FromArgs<'a>,
721 B: FromArgs<'a>,
722 C: FromArgs<'a>,
723 D: FromArgs<'a>,
724{
725 fn from_args(args: &'a Args, i: usize) -> Result<Self, KclError> {
726 let a = A::from_args(args, i)?;
727 let b = B::from_args(args, i + 1)?;
728 let c = C::from_args(args, i + 2)?;
729 let d = D::from_args(args, i + 3)?;
730 Ok((a, b, c, d))
731 }
732}
733
734impl<'a> FromKclValue<'a> for [f64; 2] {
735 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
736 let KclValue::MixedArray { value, meta: _ } = arg else {
737 return None;
738 };
739 if value.len() != 2 {
740 return None;
741 }
742 let v0 = value.first()?;
743 let v1 = value.get(1)?;
744 let array = [v0.as_f64()?, v1.as_f64()?];
745 Some(array)
746 }
747}
748
749impl<'a> FromKclValue<'a> for [usize; 3] {
750 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
751 let KclValue::MixedArray { value, meta: _ } = arg else {
752 return None;
753 };
754 if value.len() != 3 {
755 return None;
756 }
757 let v0 = value.first()?;
758 let v1 = value.get(1)?;
759 let v2 = value.get(2)?;
760 let array = [v0.as_usize()?, v1.as_usize()?, v2.as_usize()?];
761 Some(array)
762 }
763}
764
765impl<'a> FromKclValue<'a> for [f64; 3] {
766 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
767 let KclValue::MixedArray { value, meta: _ } = arg else {
768 return None;
769 };
770 if value.len() != 3 {
771 return None;
772 }
773 let v0 = value.first()?;
774 let v1 = value.get(1)?;
775 let v2 = value.get(2)?;
776 let array = [v0.as_f64()?, v1.as_f64()?, v2.as_f64()?];
777 Some(array)
778 }
779}
780
781impl<'a> FromKclValue<'a> for TagNode {
782 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
783 arg.get_tag_declarator().ok()
784 }
785}
786
787impl<'a> FromKclValue<'a> for TagIdentifier {
788 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
789 arg.get_tag_identifier().ok()
790 }
791}
792
793impl<'a> FromKclValue<'a> for KclValue {
794 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
795 Some(arg.clone())
796 }
797}
798
799macro_rules! let_field_of {
800 ($obj:ident, $field:ident?) => {
802 let $field = $obj.get(stringify!($field)).and_then(FromKclValue::from_kcl_val);
803 };
804 ($obj:ident, $field:ident? $key:literal) => {
806 let $field = $obj.get($key).and_then(FromKclValue::from_kcl_val);
807 };
808 ($obj:ident, $field:ident $key:literal) => {
810 let $field = $obj.get($key).and_then(FromKclValue::from_kcl_val)?;
811 };
812 ($obj:ident, $field:ident $(, $annotation:ty)?) => {
814 let $field $(: $annotation)? = $obj.get(stringify!($field)).and_then(FromKclValue::from_kcl_val)?;
815 };
816}
817
818impl<'a> FromKclValue<'a> for crate::std::import::ImportFormat {
819 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
820 let obj = arg.as_object()?;
821 let_field_of!(obj, typ "format");
822 match typ {
823 "fbx" => Some(Self::Fbx {}),
824 "gltf" => Some(Self::Gltf {}),
825 "sldprt" => Some(Self::Sldprt {}),
826 "step" => Some(Self::Step {}),
827 "stl" => {
828 let_field_of!(obj, coords?);
829 let_field_of!(obj, units);
830 Some(Self::Stl { coords, units })
831 }
832 "obj" => {
833 let_field_of!(obj, coords?);
834 let_field_of!(obj, units);
835 Some(Self::Obj { coords, units })
836 }
837 "ply" => {
838 let_field_of!(obj, coords?);
839 let_field_of!(obj, units);
840 Some(Self::Ply { coords, units })
841 }
842 _ => None,
843 }
844 }
845}
846
847impl<'a> FromKclValue<'a> for super::sketch::AngledLineThatIntersectsData {
848 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
849 let obj = arg.as_object()?;
850 let_field_of!(obj, angle);
851 let_field_of!(obj, intersect_tag "intersectTag");
852 let_field_of!(obj, offset?);
853 Some(Self {
854 angle,
855 intersect_tag,
856 offset,
857 })
858 }
859}
860
861impl<'a> FromKclValue<'a> for super::shapes::PolygonData {
862 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
863 let obj = arg.as_object()?;
864 let_field_of!(obj, radius);
865 let_field_of!(obj, num_sides "numSides");
866 let_field_of!(obj, center);
867 let_field_of!(obj, inscribed);
868 let polygon_type = if inscribed {
869 PolygonType::Inscribed
870 } else {
871 PolygonType::Circumscribed
872 };
873 Some(Self {
874 radius,
875 num_sides,
876 center,
877 polygon_type,
878 inscribed,
879 })
880 }
881}
882
883impl<'a> FromKclValue<'a> for crate::std::polar::PolarCoordsData {
884 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
885 let obj = arg.as_object()?;
886 let_field_of!(obj, angle);
887 let_field_of!(obj, length);
888 Some(Self { angle, length })
889 }
890}
891
892impl<'a> FromKclValue<'a> for crate::execution::Plane {
893 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
894 arg.as_plane().cloned()
895 }
896}
897
898impl<'a> FromKclValue<'a> for crate::execution::PlaneType {
899 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
900 let plane_type = match arg.as_str()? {
901 "XY" | "xy" => Self::XY,
902 "XZ" | "xz" => Self::XZ,
903 "YZ" | "yz" => Self::YZ,
904 "Custom" => Self::Custom,
905 _ => return None,
906 };
907 Some(plane_type)
908 }
909}
910
911impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::units::UnitLength {
912 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
913 let s = arg.as_str()?;
914 s.parse().ok()
915 }
916}
917
918impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::System {
919 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
920 let obj = arg.as_object()?;
921 let_field_of!(obj, forward);
922 let_field_of!(obj, up);
923 Some(Self { forward, up })
924 }
925}
926
927impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::AxisDirectionPair {
928 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
929 let obj = arg.as_object()?;
930 let_field_of!(obj, axis);
931 let_field_of!(obj, direction);
932 Some(Self { axis, direction })
933 }
934}
935
936impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::Axis {
937 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
938 let s = arg.as_str()?;
939 match s {
940 "y" => Some(Self::Y),
941 "z" => Some(Self::Z),
942 _ => None,
943 }
944 }
945}
946
947impl<'a> FromKclValue<'a> for PolygonType {
948 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
949 let s = arg.as_str()?;
950 match s {
951 "inscribed" => Some(Self::Inscribed),
952 _ => Some(Self::Circumscribed),
953 }
954 }
955}
956
957impl<'a> FromKclValue<'a> for kittycad_modeling_cmds::coord::Direction {
958 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
959 let s = arg.as_str()?;
960 match s {
961 "positive" => Some(Self::Positive),
962 "negative" => Some(Self::Negative),
963 _ => None,
964 }
965 }
966}
967
968impl<'a> FromKclValue<'a> for super::sketch::BezierData {
969 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
970 let obj = arg.as_object()?;
971 let_field_of!(obj, to);
972 let_field_of!(obj, control1);
973 let_field_of!(obj, control2);
974 Some(Self { to, control1, control2 })
975 }
976}
977
978impl<'a> FromKclValue<'a> for super::helix::HelixRevolutionsData {
979 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
980 let obj = arg.as_object()?;
981 let_field_of!(obj, revolutions);
982 let_field_of!(obj, length?);
983 let_field_of!(obj, ccw?);
984 let ccw = ccw.unwrap_or_default();
985 let angle_start = obj.get("angleStart")?.as_f64()?;
986 Some(Self {
987 revolutions,
988 angle_start,
989 ccw,
990 length,
991 })
992 }
993}
994
995impl<'a> FromKclValue<'a> for FaceTag {
996 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
997 let case1 = || match arg.as_str() {
998 Some("start" | "START") => Some(Self::StartOrEnd(super::sketch::StartOrEnd::Start)),
999 Some("end" | "END") => Some(Self::StartOrEnd(super::sketch::StartOrEnd::End)),
1000 _ => None,
1001 };
1002 let case2 = || {
1003 let tag = TagIdentifier::from_kcl_val(arg)?;
1004 Some(Self::Tag(Box::new(tag)))
1005 };
1006 case1().or_else(case2)
1007 }
1008}
1009
1010impl<'a> FromKclValue<'a> for super::sketch::AngledLineToData {
1011 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1012 let case1 = || {
1014 let obj = arg.as_object()?;
1015 let_field_of!(obj, to);
1016 let_field_of!(obj, angle);
1017 Some(Self { angle, to })
1018 };
1019 let case2 = || {
1021 let [angle, to] = arg.as_point2d()?;
1022 Some(Self { angle, to })
1023 };
1024 case1().or_else(case2)
1025 }
1026}
1027
1028impl<'a> FromKclValue<'a> for super::sketch::ArcData {
1029 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1030 let obj = arg.as_object()?;
1031 let_field_of!(obj, radius);
1032 let case1 = || {
1033 let angle_start = obj.get("angleStart")?.as_f64()?;
1034 let angle_end = obj.get("angleEnd")?.as_f64()?;
1035 Some(Self::AnglesAndRadius {
1036 angle_start,
1037 angle_end,
1038 radius,
1039 })
1040 };
1041 let case2 = || {
1042 let obj = arg.as_object()?;
1043 let_field_of!(obj, to);
1044 let_field_of!(obj, center);
1045 Some(Self::CenterToRadius { center, to, radius })
1046 };
1047 case1().or_else(case2)
1048 }
1049}
1050
1051impl<'a> FromKclValue<'a> for super::sketch::ArcToData {
1052 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1053 let obj = arg.as_object()?;
1054 let_field_of!(obj, end);
1055 let_field_of!(obj, interior);
1056 Some(Self { end, interior })
1057 }
1058}
1059
1060impl<'a> FromKclValue<'a> for super::revolve::RevolveData {
1061 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1062 let obj = arg.as_object()?;
1063 let angle = obj.get("angle").and_then(|x| x.as_f64());
1064 let tolerance = obj.get("tolerance").and_then(|x| x.as_f64());
1065 let_field_of!(obj, axis);
1066 Some(Self { angle, axis, tolerance })
1067 }
1068}
1069
1070impl<'a> FromKclValue<'a> for super::sketch::TangentialArcData {
1071 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1072 let obj = arg.as_object()?;
1073 let_field_of!(obj, radius);
1074 let_field_of!(obj, offset);
1075 Some(Self::RadiusAndOffset { radius, offset })
1076 }
1077}
1078
1079impl<'a> FromKclValue<'a> for crate::execution::Point3d {
1080 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1081 if let Some(obj) = arg.as_object() {
1083 let_field_of!(obj, x);
1084 let_field_of!(obj, y);
1085 let_field_of!(obj, z);
1086 return Some(Self { x, y, z });
1087 }
1088 let [x, y, z]: [f64; 3] = FromKclValue::from_kcl_val(arg)?;
1090 Some(Self { x, y, z })
1091 }
1092}
1093
1094impl<'a> FromKclValue<'a> for super::sketch::PlaneData {
1095 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1096 if let KclValue::Plane { value } = arg {
1098 return Some(Self::Plane {
1099 origin: value.origin,
1100 x_axis: value.x_axis,
1101 y_axis: value.y_axis,
1102 z_axis: value.z_axis,
1103 });
1104 }
1105 if let Some(s) = arg.as_str() {
1107 return match s {
1108 "XY" | "xy" => Some(Self::XY),
1109 "-XY" | "-xy" => Some(Self::NegXY),
1110 "XZ" | "xz" => Some(Self::XZ),
1111 "-XZ" | "-xz" => Some(Self::NegXZ),
1112 "YZ" | "yz" => Some(Self::YZ),
1113 "-YZ" | "-yz" => Some(Self::NegYZ),
1114 _ => None,
1115 };
1116 }
1117 let obj = arg.as_object()?;
1119 let_field_of!(obj, plane, &KclObjectFields);
1120 let origin = plane.get("origin").and_then(FromKclValue::from_kcl_val)?;
1121 let x_axis = plane.get("xAxis").and_then(FromKclValue::from_kcl_val)?;
1122 let y_axis = plane.get("yAxis").and_then(FromKclValue::from_kcl_val)?;
1123 let z_axis = plane.get("zAxis").and_then(FromKclValue::from_kcl_val)?;
1124 Some(Self::Plane {
1125 origin,
1126 x_axis,
1127 y_axis,
1128 z_axis,
1129 })
1130 }
1131}
1132
1133impl<'a> FromKclValue<'a> for crate::execution::ExtrudePlane {
1134 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1135 let obj = arg.as_object()?;
1136 let_field_of!(obj, face_id "faceId");
1137 let tag = FromKclValue::from_kcl_val(obj.get("tag")?);
1138 let_field_of!(obj, geo_meta "geoMeta");
1139 Some(Self { face_id, tag, geo_meta })
1140 }
1141}
1142
1143impl<'a> FromKclValue<'a> for crate::execution::ExtrudeArc {
1144 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1145 let obj = arg.as_object()?;
1146 let_field_of!(obj, face_id "faceId");
1147 let tag = FromKclValue::from_kcl_val(obj.get("tag")?);
1148 let_field_of!(obj, geo_meta "geoMeta");
1149 Some(Self { face_id, tag, geo_meta })
1150 }
1151}
1152
1153impl<'a> FromKclValue<'a> for crate::execution::GeoMeta {
1154 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1155 let obj = arg.as_object()?;
1156 let_field_of!(obj, id);
1157 let_field_of!(obj, source_range "sourceRange");
1158 Some(Self {
1159 id,
1160 metadata: Metadata { source_range },
1161 })
1162 }
1163}
1164
1165impl<'a> FromKclValue<'a> for crate::execution::ChamferSurface {
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::FilletSurface {
1176 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1177 let obj = arg.as_object()?;
1178 let_field_of!(obj, face_id "faceId");
1179 let tag = FromKclValue::from_kcl_val(obj.get("tag")?);
1180 let_field_of!(obj, geo_meta "geoMeta");
1181 Some(Self { face_id, tag, geo_meta })
1182 }
1183}
1184
1185impl<'a> FromKclValue<'a> for ExtrudeSurface {
1186 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1187 let case1 = crate::execution::ExtrudePlane::from_kcl_val;
1188 let case2 = crate::execution::ExtrudeArc::from_kcl_val;
1189 let case3 = crate::execution::ChamferSurface::from_kcl_val;
1190 let case4 = crate::execution::FilletSurface::from_kcl_val;
1191 case1(arg)
1192 .map(Self::ExtrudePlane)
1193 .or_else(|| case2(arg).map(Self::ExtrudeArc))
1194 .or_else(|| case3(arg).map(Self::Chamfer))
1195 .or_else(|| case4(arg).map(Self::Fillet))
1196 }
1197}
1198
1199impl<'a> FromKclValue<'a> for crate::execution::EdgeCut {
1200 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1201 let obj = arg.as_object()?;
1202 let_field_of!(obj, typ "type");
1203 let tag = Box::new(obj.get("tag").and_then(FromKclValue::from_kcl_val));
1204 let_field_of!(obj, edge_id "edgeId");
1205 let_field_of!(obj, id);
1206 match typ {
1207 "fillet" => {
1208 let_field_of!(obj, radius);
1209 Some(Self::Fillet {
1210 edge_id,
1211 tag,
1212 id,
1213 radius,
1214 })
1215 }
1216 "chamfer" => {
1217 let_field_of!(obj, length);
1218 Some(Self::Chamfer {
1219 id,
1220 length,
1221 edge_id,
1222 tag,
1223 })
1224 }
1225 _ => None,
1226 }
1227 }
1228}
1229
1230macro_rules! impl_from_kcl_for_vec {
1231 ($typ:path) => {
1232 impl<'a> FromKclValue<'a> for Vec<$typ> {
1233 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1234 arg.as_array()?
1235 .iter()
1236 .map(|value| FromKclValue::from_kcl_val(value))
1237 .collect::<Option<_>>()
1238 }
1239 }
1240 };
1241}
1242
1243impl_from_kcl_for_vec!(FaceTag);
1244impl_from_kcl_for_vec!(crate::execution::EdgeCut);
1245impl_from_kcl_for_vec!(crate::execution::Metadata);
1246impl_from_kcl_for_vec!(super::fillet::EdgeReference);
1247impl_from_kcl_for_vec!(ExtrudeSurface);
1248impl_from_kcl_for_vec!(Sketch);
1249
1250impl<'a> FromKclValue<'a> for SourceRange {
1251 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1252 let KclValue::MixedArray { value, meta: _ } = arg else {
1253 return None;
1254 };
1255 if value.len() != 3 {
1256 return None;
1257 }
1258 let v0 = value.first()?;
1259 let v1 = value.get(1)?;
1260 let v2 = value.get(2)?;
1261 Some(SourceRange::new(
1262 v0.as_usize()?,
1263 v1.as_usize()?,
1264 ModuleId::from_usize(v2.as_usize()?),
1265 ))
1266 }
1267}
1268
1269impl<'a> FromKclValue<'a> for crate::execution::Metadata {
1270 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1271 FromKclValue::from_kcl_val(arg).map(|sr| Self { source_range: sr })
1272 }
1273}
1274
1275impl<'a> FromKclValue<'a> for crate::execution::Solid {
1276 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1277 arg.as_solid().cloned()
1278 }
1279}
1280
1281impl<'a> FromKclValue<'a> for super::sketch::SketchData {
1282 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1283 let case1 = crate::execution::Plane::from_kcl_val;
1285 let case2 = super::sketch::PlaneData::from_kcl_val;
1286 let case3 = crate::execution::Solid::from_kcl_val;
1287 case1(arg)
1288 .map(Box::new)
1289 .map(Self::Plane)
1290 .or_else(|| case2(arg).map(Self::PlaneOrientation))
1291 .or_else(|| case3(arg).map(Box::new).map(Self::Solid))
1292 }
1293}
1294
1295impl<'a> FromKclValue<'a> for super::axis_or_reference::AxisAndOrigin2d {
1296 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1297 if let Some(s) = arg.as_str() {
1299 return match s {
1300 "X" | "x" => Some(Self::X),
1301 "Y" | "y" => Some(Self::Y),
1302 "-X" | "-x" => Some(Self::NegX),
1303 "-Y" | "-y" => Some(Self::NegY),
1304 _ => None,
1305 };
1306 }
1307 let obj = arg.as_object()?;
1309 let_field_of!(obj, custom, &KclObjectFields);
1310 let_field_of!(custom, origin);
1311 let_field_of!(custom, axis);
1312 Some(Self::Custom { axis, origin })
1313 }
1314}
1315
1316impl<'a> FromKclValue<'a> for super::axis_or_reference::AxisAndOrigin3d {
1317 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1318 if let Some(s) = arg.as_str() {
1320 return match s {
1321 "X" | "x" => Some(Self::X),
1322 "Y" | "y" => Some(Self::Y),
1323 "Z" | "z" => Some(Self::Z),
1324 "-X" | "-x" => Some(Self::NegX),
1325 "-Y" | "-y" => Some(Self::NegY),
1326 "-Z" | "-z" => Some(Self::NegZ),
1327 _ => None,
1328 };
1329 }
1330 let obj = arg.as_object()?;
1332 let_field_of!(obj, custom, &KclObjectFields);
1333 let_field_of!(custom, origin);
1334 let_field_of!(custom, axis);
1335 Some(Self::Custom { axis, origin })
1336 }
1337}
1338
1339impl<'a> FromKclValue<'a> for super::fillet::EdgeReference {
1340 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1341 let id = arg.as_uuid().map(Self::Uuid);
1342 let tag = || TagIdentifier::from_kcl_val(arg).map(Box::new).map(Self::Tag);
1343 id.or_else(tag)
1344 }
1345}
1346
1347impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis2dOrEdgeReference {
1348 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1349 let case1 = super::axis_or_reference::AxisAndOrigin2d::from_kcl_val;
1350 let case2 = super::fillet::EdgeReference::from_kcl_val;
1351 case1(arg).map(Self::Axis).or_else(|| case2(arg).map(Self::Edge))
1352 }
1353}
1354
1355impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis3dOrEdgeReference {
1356 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1357 let case1 = super::axis_or_reference::AxisAndOrigin3d::from_kcl_val;
1358 let case2 = super::fillet::EdgeReference::from_kcl_val;
1359 case1(arg).map(Self::Axis).or_else(|| case2(arg).map(Self::Edge))
1360 }
1361}
1362
1363impl<'a> FromKclValue<'a> for super::mirror::Mirror2dData {
1364 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1365 let obj = arg.as_object()?;
1366 let_field_of!(obj, axis);
1367 Some(Self { axis })
1368 }
1369}
1370
1371impl<'a> FromKclValue<'a> for super::sketch::AngledLineData {
1372 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1373 let case1 = |arg: &KclValue| {
1374 let obj = arg.as_object()?;
1375 let_field_of!(obj, angle);
1376 let_field_of!(obj, length);
1377 Some(Self::AngleAndLengthNamed { angle, length })
1378 };
1379 let case2 = |arg: &KclValue| {
1380 let array = arg.as_array()?;
1381 let ang = array.first()?.as_f64()?;
1382 let len = array.get(1)?.as_f64()?;
1383 Some(Self::AngleAndLengthPair([ang, len]))
1384 };
1385 case1(arg).or_else(|| case2(arg))
1386 }
1387}
1388
1389impl<'a> FromKclValue<'a> for i64 {
1390 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1391 match arg {
1392 KclValue::Number { value, .. } => crate::try_f64_to_i64(*value),
1393 _ => None,
1394 }
1395 }
1396}
1397
1398impl<'a> FromKclValue<'a> for &'a str {
1399 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1400 let KclValue::String { value, meta: _ } = arg else {
1401 return None;
1402 };
1403 Some(value)
1404 }
1405}
1406
1407impl<'a> FromKclValue<'a> for &'a KclObjectFields {
1408 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1409 let KclValue::Object { value, meta: _ } = arg else {
1410 return None;
1411 };
1412 Some(value)
1413 }
1414}
1415
1416impl<'a> FromKclValue<'a> for uuid::Uuid {
1417 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1418 let KclValue::Uuid { value, meta: _ } = arg else {
1419 return None;
1420 };
1421 Some(*value)
1422 }
1423}
1424
1425impl<'a> FromKclValue<'a> for u32 {
1426 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1427 match arg {
1428 KclValue::Number { value, .. } => crate::try_f64_to_u32(*value),
1429 _ => None,
1430 }
1431 }
1432}
1433
1434impl<'a> FromKclValue<'a> for NonZeroU32 {
1435 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1436 u32::from_kcl_val(arg).and_then(|x| x.try_into().ok())
1437 }
1438}
1439
1440impl<'a> FromKclValue<'a> for u64 {
1441 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1442 match arg {
1443 KclValue::Number { value, .. } => crate::try_f64_to_u64(*value),
1444 _ => None,
1445 }
1446 }
1447}
1448impl<'a> FromKclValue<'a> for f64 {
1449 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1450 match arg {
1451 KclValue::Number { value, .. } => Some(*value),
1452 _ => None,
1453 }
1454 }
1455}
1456impl<'a> FromKclValue<'a> for TyF64 {
1457 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1458 match arg {
1459 KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, ty.clone())),
1460 _ => None,
1461 }
1462 }
1463}
1464impl<'a> FromKclValue<'a> for Sketch {
1465 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1466 let KclValue::Sketch { value } = arg else {
1467 return None;
1468 };
1469 Some(value.as_ref().to_owned())
1470 }
1471}
1472
1473impl<'a> FromKclValue<'a> for Helix {
1474 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1475 let KclValue::Helix { value } = arg else {
1476 return None;
1477 };
1478 Some(value.as_ref().to_owned())
1479 }
1480}
1481impl<'a> FromKclValue<'a> for SweepPath {
1482 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1483 let case1 = Sketch::from_kcl_val;
1484 let case2 = Helix::from_kcl_val;
1485 case1(arg)
1486 .map(Self::Sketch)
1487 .or_else(|| case2(arg).map(|arg0: Helix| Self::Helix(Box::new(arg0))))
1488 }
1489}
1490impl<'a> FromKclValue<'a> for String {
1491 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1492 let KclValue::String { value, meta: _ } = arg else {
1493 return None;
1494 };
1495 Some(value.to_owned())
1496 }
1497}
1498impl<'a> FromKclValue<'a> for crate::parsing::ast::types::KclNone {
1499 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1500 let KclValue::KclNone { value, meta: _ } = arg else {
1501 return None;
1502 };
1503 Some(value.to_owned())
1504 }
1505}
1506impl<'a> FromKclValue<'a> for bool {
1507 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1508 let KclValue::Bool { value, meta: _ } = arg else {
1509 return None;
1510 };
1511 Some(*value)
1512 }
1513}
1514
1515impl<'a> FromKclValue<'a> for SketchSet {
1516 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1517 match arg {
1518 KclValue::Sketch { value: sketch } => Some(SketchSet::from(sketch.to_owned())),
1519 KclValue::Sketches { value } => Some(SketchSet::from(value.to_owned())),
1520 KclValue::MixedArray { .. } => {
1521 let v: Option<Vec<Sketch>> = FromKclValue::from_kcl_val(arg);
1522 Some(SketchSet::Sketches(v?.iter().cloned().map(Box::new).collect()))
1523 }
1524 _ => None,
1525 }
1526 }
1527}
1528
1529impl<'a> FromKclValue<'a> for Box<Solid> {
1530 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1531 let KclValue::Solid { value } = arg else {
1532 return None;
1533 };
1534 Some(value.to_owned())
1535 }
1536}
1537
1538impl<'a> FromKclValue<'a> for &'a FunctionSource {
1539 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1540 arg.get_function()
1541 }
1542}
1543
1544impl<'a> FromKclValue<'a> for SolidSet {
1545 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1546 arg.get_solid_set().ok()
1547 }
1548}
1549
1550impl<'a> FromKclValue<'a> for SketchOrSurface {
1551 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1552 match arg {
1553 KclValue::Sketch { value: sg } => Some(Self::Sketch(sg.to_owned())),
1554 KclValue::Plane { value } => Some(Self::SketchSurface(SketchSurface::Plane(value.clone()))),
1555 KclValue::Face { value } => Some(Self::SketchSurface(SketchSurface::Face(value.clone()))),
1556 _ => None,
1557 }
1558 }
1559}
1560impl<'a> FromKclValue<'a> for SketchSurface {
1561 fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
1562 match arg {
1563 KclValue::Plane { value } => Some(Self::Plane(value.clone())),
1564 KclValue::Face { value } => Some(Self::Face(value.clone())),
1565 _ => None,
1566 }
1567 }
1568}
1569
1570impl From<Args> for Metadata {
1571 fn from(value: Args) -> Self {
1572 Self {
1573 source_range: value.source_range,
1574 }
1575 }
1576}
1577
1578impl From<Args> for Vec<Metadata> {
1579 fn from(value: Args) -> Self {
1580 vec![Metadata {
1581 source_range: value.source_range,
1582 }]
1583 }
1584}