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