use crate::{
ast::types::{parse_json_number_as_f64, TagDeclarator},
errors::{KclError, KclErrorDetails},
executor::{
ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, MemoryItem, Metadata, ProgramMemory,
SketchGroup, SketchGroupSet, SketchSurface, SourceRange, TagIdentifier,
},
};
use kittycad::types::OkWebSocketResponseData;
use super::{sketch::FaceTag, FnAsArg};
#[derive(Debug, Clone)]
pub struct Args {
pub args: Vec<MemoryItem>,
pub source_range: SourceRange,
pub ctx: ExecutorContext,
pub current_program_memory: ProgramMemory,
}
impl Args {
pub fn new(
args: Vec<MemoryItem>,
source_range: SourceRange,
ctx: ExecutorContext,
current_program_memory: ProgramMemory,
) -> Self {
Self {
args,
source_range,
ctx,
current_program_memory,
}
}
pub async fn batch_modeling_cmd(
&self,
id: uuid::Uuid,
cmd: kittycad::types::ModelingCmd,
) -> Result<(), crate::errors::KclError> {
self.ctx.engine.batch_modeling_cmd(id, self.source_range, &cmd).await
}
pub async fn batch_end_cmd(
&self,
id: uuid::Uuid,
cmd: kittycad::types::ModelingCmd,
) -> Result<(), crate::errors::KclError> {
self.ctx.engine.batch_end_cmd(id, self.source_range, &cmd).await
}
pub async fn send_modeling_cmd(
&self,
id: uuid::Uuid,
cmd: kittycad::types::ModelingCmd,
) -> Result<OkWebSocketResponseData, KclError> {
self.ctx.engine.send_modeling_cmd(id, self.source_range, cmd).await
}
pub async fn flush_batch_for_extrude_group_set(
&self,
extrude_groups: Vec<Box<ExtrudeGroup>>,
) -> Result<(), KclError> {
let mut traversed_sketch_groups = Vec::new();
let mut ids = Vec::new();
for extrude_group in extrude_groups {
let sketch_group_id = extrude_group.sketch_group.id;
if !traversed_sketch_groups.contains(&sketch_group_id) {
ids.extend(
self.current_program_memory
.find_extrude_groups_on_sketch_group(extrude_group.sketch_group.id)
.iter()
.flat_map(|eg| eg.get_all_fillet_or_chamfer_ids()),
);
traversed_sketch_groups.push(sketch_group_id);
}
ids.extend(extrude_group.get_all_fillet_or_chamfer_ids());
}
if ids.is_empty() {
return Ok(());
}
for id in ids {
let Some(item) = self.ctx.engine.batch_end().lock().unwrap().remove(&id) else {
continue;
};
self.ctx.engine.batch().lock().unwrap().push(item);
}
self.ctx.engine.flush_batch(false, SourceRange::default()).await?;
Ok(())
}
fn make_user_val_from_json(&self, j: serde_json::Value) -> Result<MemoryItem, KclError> {
Ok(MemoryItem::UserVal(crate::executor::UserVal {
value: j,
meta: vec![Metadata {
source_range: self.source_range,
}],
}))
}
pub fn make_user_val_from_f64(&self, f: f64) -> Result<MemoryItem, KclError> {
self.make_user_val_from_json(serde_json::Value::Number(serde_json::Number::from_f64(f).ok_or_else(
|| {
KclError::Type(KclErrorDetails {
message: format!("Failed to convert `{}` to a number", f),
source_ranges: vec![self.source_range],
})
},
)?))
}
pub fn get_number(&self) -> Result<f64, KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a number as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
parse_json_number_as_f64(&first_value, self.source_range)
}
pub fn get_number_array(&self) -> Result<Vec<f64>, KclError> {
let mut numbers: Vec<f64> = Vec::new();
for arg in &self.args {
let parsed = arg.get_json_value()?;
numbers.push(parse_json_number_as_f64(&parsed, self.source_range)?);
}
Ok(numbers)
}
pub fn get_pattern_transform_args(&self) -> Result<(u32, FnAsArg<'_>, ExtrudeGroupSet), KclError> {
let sr = vec![self.source_range];
let mut args = self.args.iter();
let num_repetitions = args.next().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: "Missing first argument (should be the number of repetitions)".to_owned(),
source_ranges: sr.clone(),
})
})?;
let num_repetitions = num_repetitions.get_u32(sr.clone())?;
let transform = args.next().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: "Missing second argument (should be the transform function)".to_owned(),
source_ranges: sr.clone(),
})
})?;
let func = transform.get_function(sr.clone())?;
let eg = args.next().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: "Missing third argument (should be a Sketch/ExtrudeGroup or an array of Sketch/ExtrudeGroups)"
.to_owned(),
source_ranges: sr.clone(),
})
})?;
let eg = eg.get_extrude_group_set().map_err(|_e| {
KclError::Type(KclErrorDetails {
message: "Third argument was not an ExtrudeGroup".to_owned(),
source_ranges: sr.clone(),
})
})?;
Ok((num_repetitions, func, eg))
}
pub fn get_hypotenuse_leg(&self) -> Result<(f64, f64), KclError> {
let numbers = self.get_number_array()?;
if numbers.len() != 2 {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a number array of length 2, found `{:?}`", numbers),
source_ranges: vec![self.source_range],
}));
}
Ok((numbers[0], numbers[1]))
}
pub fn get_circle_args(
&self,
) -> Result<
(
[f64; 2],
f64,
crate::std::shapes::SketchSurfaceOrGroup,
Option<TagDeclarator>,
),
KclError,
> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
"Expected a [number, number] as the first argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let center: [f64; 2] = if let serde_json::Value::Array(arr) = first_value {
if arr.len() != 2 {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected a [number, number] as the first argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
}
let x = parse_json_number_as_f64(&arr[0], self.source_range)?;
let y = parse_json_number_as_f64(&arr[1], self.source_range)?;
[x, y]
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected a [number, number] as the first argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
let second_value = self
.args
.get(1)
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a number as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let radius: f64 = serde_json::from_value(second_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize number from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let third_value = self.args.get(2).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
"Expected a SketchGroup or SketchSurface as the third argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
})
})?;
let sketch_group_or_surface = if let MemoryItem::SketchGroup(sg) = third_value {
crate::std::shapes::SketchSurfaceOrGroup::SketchGroup(sg.clone())
} else if let MemoryItem::Plane(sg) = third_value {
crate::std::shapes::SketchSurfaceOrGroup::SketchSurface(SketchSurface::Plane(sg.clone()))
} else if let MemoryItem::Face(sg) = third_value {
crate::std::shapes::SketchSurfaceOrGroup::SketchSurface(SketchSurface::Face(sg.clone()))
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected a SketchGroup or SketchSurface as the third argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
let tag = if let Some(tag) = self.args.get(3) {
tag.get_tag_declarator_opt()?
} else {
None
};
Ok((center, radius, sketch_group_or_surface, tag))
}
pub fn get_segment_name_sketch_group(&self) -> Result<(TagIdentifier, Box<SketchGroup>), KclError> {
let first_value = self.args.first().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a string as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let segment_name = first_value.get_tag_identifier()?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_group = if let MemoryItem::SketchGroup(sg) = second_value {
sg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
}));
};
Ok((segment_name, sketch_group))
}
pub fn get_sketch_groups(&self) -> Result<(SketchGroupSet, Box<SketchGroup>), KclError> {
let first_value = self.args.first().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_set = match first_value.get_sketch_group_set() {
Ok(set) => set,
Err(err) => {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected an SketchGroupSet as the first argument: {}", err),
source_ranges: vec![self.source_range],
}))
}
};
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_group = if let MemoryItem::SketchGroup(sg) = second_value {
sg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
}));
};
Ok((sketch_set, sketch_group))
}
pub fn get_sketch_group(&self) -> Result<Box<SketchGroup>, KclError> {
let first_value = self.args.first().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_group = if let MemoryItem::SketchGroup(sg) = first_value {
sg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
}));
};
Ok(sketch_group)
}
pub fn get_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
Ok(data)
}
pub fn get_import_data(&self) -> Result<(String, Option<crate::std::import::ImportFormat>), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: String = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Expected a file path string: {}", e),
source_ranges: vec![self.source_range],
})
})?;
if let Some(second_value) = self.args.get(1) {
let options: crate::std::import::ImportFormat = serde_json::from_value(second_value.get_json_value()?)
.map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Expected input format data: {}", e),
source_ranges: vec![self.source_range],
})
})?;
Ok((data, Some(options)))
} else {
Ok((data, None))
}
}
pub fn get_sketch_group_and_optional_tag(&self) -> Result<(Box<SketchGroup>, Option<TagDeclarator>), KclError> {
let first_value = self.args.first().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_group = if let MemoryItem::SketchGroup(sg) = first_value {
sg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
}));
};
let tag = if let Some(tag) = self.args.get(1) {
tag.get_tag_declarator_opt()?
} else {
None
};
Ok((sketch_group, tag))
}
pub fn get_data_and_optional_tag<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Option<FaceTag>), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
if let Some(second_value) = self.args.get(1) {
let tag: FaceTag = serde_json::from_value(second_value.get_json_value()?).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize FaceTag from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
Ok((data, Some(tag)))
} else {
Ok((data, None))
}
}
pub fn get_data_and_sketch_group<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Box<SketchGroup>), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_group = if let MemoryItem::SketchGroup(sg) = second_value {
sg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
}));
};
Ok((data, sketch_group))
}
pub fn get_data_and_sketch_group_set<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, SketchGroupSet), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_set = match second_value.get_sketch_group_set() {
Ok(set) => set,
Err(err) => {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected an SketchGroupSet as the second argument: {}", err),
source_ranges: vec![self.source_range],
}))
}
};
Ok((data, sketch_set))
}
pub fn get_data_and_sketch_group_and_tag<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, Box<SketchGroup>, Option<TagDeclarator>), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_group = if let MemoryItem::SketchGroup(sg) = second_value {
sg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
}));
};
let tag = if let Some(tag) = self.args.get(2) {
tag.get_tag_declarator_opt()?
} else {
None
};
Ok((data, sketch_group, tag))
}
pub fn get_data_and_sketch_surface<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, SketchSurface, Option<TagDeclarator>), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a Plane as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_surface = if let MemoryItem::Plane(p) = second_value {
SketchSurface::Plane(p.clone())
} else if let MemoryItem::Face(face) = second_value {
SketchSurface::Face(face.clone())
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected a plane or face (SketchSurface) as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
let tag = if let Some(tag) = self.args.get(2) {
tag.get_tag_declarator_opt()?
} else {
None
};
Ok((data, sketch_surface, tag))
}
pub fn get_data_and_extrude_group_set<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, ExtrudeGroupSet), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
})
})?;
let extrude_set = match second_value.get_extrude_group_set() {
Ok(set) => set,
Err(err) => {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected an ExtrudeGroupSet as the second argument: {}", err),
source_ranges: vec![self.source_range],
}))
}
};
Ok((data, extrude_set))
}
pub fn get_data_and_extrude_group<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, Box<ExtrudeGroup>), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
})
})?;
let extrude_group = if let MemoryItem::ExtrudeGroup(eg) = second_value {
eg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
Ok((data, extrude_group))
}
pub fn get_data_and_extrude_group_and_tag<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, Box<ExtrudeGroup>, Option<TagDeclarator>), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let data: T = serde_json::from_value(first_value).map_err(|e| {
KclError::Type(KclErrorDetails {
message: format!("Failed to deserialize struct from JSON: {}", e),
source_ranges: vec![self.source_range],
})
})?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
})
})?;
let extrude_group = if let MemoryItem::ExtrudeGroup(eg) = second_value {
eg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
let tag = if let Some(tag) = self.args.get(2) {
tag.get_tag_declarator_opt()?
} else {
None
};
Ok((data, extrude_group, tag))
}
pub fn get_tag_and_extrude_group(&self) -> Result<(TagIdentifier, Box<ExtrudeGroup>), KclError> {
let first_value = self.args.first().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let tag = first_value.get_tag_identifier()?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
})
})?;
let extrude_group = if let MemoryItem::ExtrudeGroup(eg) = second_value {
eg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
Ok((tag, extrude_group))
}
pub fn get_segment_name_to_number_sketch_group(&self) -> Result<(TagIdentifier, f64, Box<SketchGroup>), KclError> {
let first_value = self.args.first().ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a string as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let segment_name = first_value.get_tag_identifier()?;
let second_value = self
.args
.get(1)
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a number as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let to_number = parse_json_number_as_f64(&second_value, self.source_range)?;
let third_value = self.args.get(2).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the third argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_group = if let MemoryItem::SketchGroup(sg) = third_value {
sg.clone()
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the third argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
}));
};
Ok((segment_name, to_number, sketch_group))
}
pub fn get_number_sketch_group_set(&self) -> Result<(f64, SketchGroupSet), KclError> {
let first_value = self
.args
.first()
.ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a number as the first argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?
.get_json_value()?;
let number = parse_json_number_as_f64(&first_value, self.source_range)?;
let second_value = self.args.get(1).ok_or_else(|| {
KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_set = match second_value.get_sketch_group_set() {
Ok(set) => set,
Err(err) => {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected an SketchGroupSet as the second argument: {}", err),
source_ranges: vec![self.source_range],
}))
}
};
Ok((number, sketch_set))
}
pub async fn get_adjacent_face_to_tag(
&self,
extrude_group: &ExtrudeGroup,
tag: &TagIdentifier,
must_be_planar: bool,
) -> Result<uuid::Uuid, KclError> {
if tag.value.is_empty() {
return Err(KclError::Type(KclErrorDetails {
message: "Expected a non-empty tag for the face".to_string(),
source_ranges: vec![self.source_range],
}));
}
if let Some(face_from_surface) = extrude_group
.value
.iter()
.find_map(|extrude_surface| match extrude_surface {
ExtrudeSurface::ExtrudePlane(extrude_plane) => {
if let Some(plane_tag) = &extrude_plane.tag {
if plane_tag.name == tag.value {
Some(Ok(extrude_plane.face_id))
} else {
None
}
} else {
None
}
}
ExtrudeSurface::ExtrudeArc(_) if must_be_planar => Some(Err(KclError::Type(KclErrorDetails {
message: format!("Tag `{}` is a non-planar surface", tag.value),
source_ranges: vec![self.source_range],
}))),
ExtrudeSurface::ExtrudeArc(extrude_arc) => {
if let Some(arc_tag) = &extrude_arc.tag {
if arc_tag.name == tag.value {
Some(Ok(extrude_arc.face_id))
} else {
None
}
} else {
None
}
}
})
{
return face_from_surface;
}
if let Some(face_from_chamfer_fillet) = extrude_group.fillet_or_chamfers.iter().find_map(|fc| {
if let Some(ntag) = &fc.tag() {
if ntag.name == tag.value {
Some(Ok(fc.id()))
} else {
None
}
} else {
None
}
}) {
self.flush_batch_for_extrude_group_set(extrude_group.into()).await?;
return face_from_chamfer_fillet;
}
Err(KclError::Type(KclErrorDetails {
message: format!("Expected a face with the tag `{}`", tag.value),
source_ranges: vec![self.source_range],
}))
}
}