1pub mod appearance;
4pub mod args;
5pub mod array;
6pub mod assert;
7pub mod axis_or_reference;
8pub mod chamfer;
9pub mod convert;
10pub mod csg;
11pub mod edge;
12pub mod extrude;
13pub mod fillet;
14pub mod helix;
15pub mod import;
16pub mod loft;
17pub mod math;
18pub mod mirror;
19pub mod patterns;
20pub mod planes;
21pub mod polar;
22pub mod revolve;
23pub mod segment;
24pub mod shapes;
25pub mod shell;
26pub mod sketch;
27pub mod sweep;
28pub mod transform;
29pub mod types;
30pub mod units;
31pub mod utils;
32
33use anyhow::Result;
34pub use args::Args;
35use indexmap::IndexMap;
36use kcl_derive_docs::stdlib;
37use lazy_static::lazy_static;
38use parse_display::{Display, FromStr};
39use schemars::JsonSchema;
40use serde::{Deserialize, Serialize};
41
42use crate::{
43 docs::StdLibFn,
44 errors::KclError,
45 execution::{ExecState, KclValue},
46};
47
48pub type StdFn = fn(
49 &mut ExecState,
50 Args,
51) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<KclValue, KclError>> + Send + '_>>;
52
53lazy_static! {
54 static ref CORE_FNS: Vec<Box<dyn StdLibFn>> = vec![
55 Box::new(LegLen),
56 Box::new(LegAngX),
57 Box::new(LegAngY),
58 Box::new(crate::std::appearance::Appearance),
59 Box::new(crate::std::convert::Int),
60 Box::new(crate::std::extrude::Extrude),
61 Box::new(crate::std::segment::SegEnd),
62 Box::new(crate::std::segment::SegEndX),
63 Box::new(crate::std::segment::SegEndY),
64 Box::new(crate::std::segment::SegStart),
65 Box::new(crate::std::segment::SegStartX),
66 Box::new(crate::std::segment::SegStartY),
67 Box::new(crate::std::segment::LastSegX),
68 Box::new(crate::std::segment::LastSegY),
69 Box::new(crate::std::segment::SegLen),
70 Box::new(crate::std::segment::SegAng),
71 Box::new(crate::std::segment::TangentToEnd),
72 Box::new(crate::std::segment::AngleToMatchLengthX),
73 Box::new(crate::std::segment::AngleToMatchLengthY),
74 Box::new(crate::std::shapes::Circle),
75 Box::new(crate::std::shapes::CircleThreePoint),
76 Box::new(crate::std::shapes::Polygon),
77 Box::new(crate::std::sketch::Line),
78 Box::new(crate::std::sketch::XLine),
79 Box::new(crate::std::sketch::YLine),
80 Box::new(crate::std::sketch::AngledLineToX),
81 Box::new(crate::std::sketch::AngledLineToY),
82 Box::new(crate::std::sketch::AngledLine),
83 Box::new(crate::std::sketch::AngledLineOfXLength),
84 Box::new(crate::std::sketch::AngledLineOfYLength),
85 Box::new(crate::std::sketch::AngledLineThatIntersects),
86 Box::new(crate::std::sketch::StartSketchOn),
87 Box::new(crate::std::sketch::StartProfileAt),
88 Box::new(crate::std::sketch::ProfileStartX),
89 Box::new(crate::std::sketch::ProfileStartY),
90 Box::new(crate::std::sketch::ProfileStart),
91 Box::new(crate::std::sketch::Close),
92 Box::new(crate::std::sketch::Arc),
93 Box::new(crate::std::sketch::ArcTo),
94 Box::new(crate::std::sketch::TangentialArc),
95 Box::new(crate::std::sketch::TangentialArcTo),
96 Box::new(crate::std::sketch::TangentialArcToRelative),
97 Box::new(crate::std::sketch::BezierCurve),
98 Box::new(crate::std::sketch::Hole),
99 Box::new(crate::std::mirror::Mirror2D),
100 Box::new(crate::std::patterns::PatternLinear2D),
101 Box::new(crate::std::patterns::PatternLinear3D),
102 Box::new(crate::std::patterns::PatternCircular2D),
103 Box::new(crate::std::patterns::PatternCircular3D),
104 Box::new(crate::std::patterns::PatternTransform),
105 Box::new(crate::std::patterns::PatternTransform2D),
106 Box::new(crate::std::array::Reduce),
107 Box::new(crate::std::array::Map),
108 Box::new(crate::std::array::Push),
109 Box::new(crate::std::array::Pop),
110 Box::new(crate::std::chamfer::Chamfer),
111 Box::new(crate::std::fillet::Fillet),
112 Box::new(crate::std::edge::GetOppositeEdge),
113 Box::new(crate::std::edge::GetNextAdjacentEdge),
114 Box::new(crate::std::edge::GetPreviousAdjacentEdge),
115 Box::new(crate::std::edge::GetCommonEdge),
116 Box::new(crate::std::helix::Helix),
117 Box::new(crate::std::helix::HelixRevolutions),
118 Box::new(crate::std::shell::Shell),
119 Box::new(crate::std::shell::Hollow),
120 Box::new(crate::std::revolve::Revolve),
121 Box::new(crate::std::sweep::Sweep),
122 Box::new(crate::std::loft::Loft),
123 Box::new(crate::std::planes::OffsetPlane),
124 Box::new(crate::std::import::Import),
125 Box::new(crate::std::math::Acos),
126 Box::new(crate::std::math::Asin),
127 Box::new(crate::std::math::Atan),
128 Box::new(crate::std::math::Atan2),
129 Box::new(crate::std::math::Pi),
130 Box::new(crate::std::math::E),
131 Box::new(crate::std::math::Tau),
132 Box::new(crate::std::math::Sqrt),
133 Box::new(crate::std::math::Abs),
134 Box::new(crate::std::math::Rem),
135 Box::new(crate::std::math::Round),
136 Box::new(crate::std::math::Floor),
137 Box::new(crate::std::math::Ceil),
138 Box::new(crate::std::math::Min),
139 Box::new(crate::std::math::Max),
140 Box::new(crate::std::math::Pow),
141 Box::new(crate::std::math::Log),
142 Box::new(crate::std::math::Log2),
143 Box::new(crate::std::math::Log10),
144 Box::new(crate::std::math::Ln),
145 Box::new(crate::std::math::ToDegrees),
146 Box::new(crate::std::math::ToRadians),
147 Box::new(crate::std::units::Mm),
148 Box::new(crate::std::units::Inch),
149 Box::new(crate::std::units::Ft),
150 Box::new(crate::std::units::M),
151 Box::new(crate::std::units::Cm),
152 Box::new(crate::std::units::Yd),
153 Box::new(crate::std::polar::Polar),
154 Box::new(crate::std::assert::Assert),
155 Box::new(crate::std::assert::AssertEqual),
156 Box::new(crate::std::assert::AssertLessThan),
157 Box::new(crate::std::assert::AssertGreaterThan),
158 Box::new(crate::std::assert::AssertLessThanOrEq),
159 Box::new(crate::std::assert::AssertGreaterThanOrEq),
160 Box::new(crate::std::transform::Scale),
161 Box::new(crate::std::transform::Translate),
162 Box::new(crate::std::transform::Rotate),
163 Box::new(crate::std::csg::Intersect),
164 Box::new(crate::std::csg::Union),
165 Box::new(crate::std::csg::Subtract),
166 ];
167}
168
169pub fn name_in_stdlib(name: &str) -> bool {
170 CORE_FNS.iter().any(|f| f.name() == name)
171}
172
173pub fn get_stdlib_fn(name: &str) -> Option<Box<dyn StdLibFn>> {
174 CORE_FNS.iter().find(|f| f.name() == name).cloned()
175}
176
177#[derive(Clone, Debug, PartialEq, Eq)]
178pub struct StdFnProps {
179 pub name: String,
180 pub deprecated: bool,
181}
182
183impl StdFnProps {
184 fn default(name: &str) -> Self {
185 Self {
186 name: name.to_owned(),
187 deprecated: false,
188 }
189 }
190}
191
192pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProps) {
193 match (path, fn_name) {
194 ("math", "cos") => (
195 |e, a| Box::pin(crate::std::math::cos(e, a)),
196 StdFnProps::default("std::math::cos"),
197 ),
198 ("math", "sin") => (
199 |e, a| Box::pin(crate::std::math::sin(e, a)),
200 StdFnProps::default("std::math::sin"),
201 ),
202 ("math", "tan") => (
203 |e, a| Box::pin(crate::std::math::tan(e, a)),
204 StdFnProps::default("std::math::tan"),
205 ),
206 _ => unreachable!(),
207 }
208}
209
210pub(crate) fn std_ty(path: &str, fn_name: &str) -> (crate::execution::PrimitiveType, StdFnProps) {
211 match (path, fn_name) {
212 ("prelude", "Sketch") => (
213 crate::execution::PrimitiveType::Sketch,
214 StdFnProps::default("std::Sketch"),
215 ),
216 ("prelude", "Solid") => (
217 crate::execution::PrimitiveType::Solid,
218 StdFnProps::default("std::Solid"),
219 ),
220 ("prelude", "Plane") => (
221 crate::execution::PrimitiveType::Plane,
222 StdFnProps::default("std::Plane"),
223 ),
224 _ => unreachable!(),
225 }
226}
227
228pub struct StdLib {
229 pub fns: IndexMap<String, Box<dyn StdLibFn>>,
230}
231
232impl std::fmt::Debug for StdLib {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 f.debug_struct("StdLib").field("fns.len()", &self.fns.len()).finish()
235 }
236}
237
238impl StdLib {
239 pub fn new() -> Self {
240 let fns = CORE_FNS
241 .clone()
242 .into_iter()
243 .map(|internal_fn| (internal_fn.name(), internal_fn))
244 .collect();
245
246 Self { fns }
247 }
248
249 pub fn combined(&self) -> IndexMap<String, Box<dyn StdLibFn>> {
251 self.fns.clone()
252 }
253
254 pub fn get(&self, name: &str) -> Option<Box<dyn StdLibFn>> {
255 self.fns.get(name).cloned()
256 }
257
258 pub fn get_either(&self, name: &str) -> FunctionKind {
259 if let Some(f) = self.get(name) {
260 FunctionKind::Core(f)
261 } else {
262 FunctionKind::UserDefined
263 }
264 }
265
266 pub fn contains_key(&self, key: &str) -> bool {
267 self.fns.contains_key(key)
268 }
269}
270
271impl Default for StdLib {
272 fn default() -> Self {
273 Self::new()
274 }
275}
276
277#[derive(Debug)]
278pub enum FunctionKind {
279 Core(Box<dyn StdLibFn>),
280 UserDefined,
281}
282
283pub async fn leg_length(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
285 let (hypotenuse, leg, ty) = args.get_hypotenuse_leg()?;
286 let result = inner_leg_length(hypotenuse, leg);
287 Ok(KclValue::from_number_with_type(result, ty, vec![args.into()]))
288}
289
290#[stdlib {
296 name = "legLen",
297 tags = ["utilities"],
298}]
299fn inner_leg_length(hypotenuse: f64, leg: f64) -> f64 {
300 (hypotenuse.powi(2) - f64::min(hypotenuse.abs(), leg.abs()).powi(2)).sqrt()
301}
302
303pub async fn leg_angle_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
305 let (hypotenuse, leg, ty) = args.get_hypotenuse_leg()?;
306 let result = inner_leg_angle_x(hypotenuse, leg);
307 Ok(KclValue::from_number_with_type(result, ty, vec![args.into()]))
308}
309
310#[stdlib {
316 name = "legAngX",
317 tags = ["utilities"],
318}]
319fn inner_leg_angle_x(hypotenuse: f64, leg: f64) -> f64 {
320 (leg.min(hypotenuse) / hypotenuse).acos().to_degrees()
321}
322
323pub async fn leg_angle_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
325 let (hypotenuse, leg, ty) = args.get_hypotenuse_leg()?;
326 let result = inner_leg_angle_y(hypotenuse, leg);
327 Ok(KclValue::from_number_with_type(result, ty, vec![args.into()]))
328}
329
330#[stdlib {
336 name = "legAngY",
337 tags = ["utilities"],
338}]
339fn inner_leg_angle_y(hypotenuse: f64, leg: f64) -> f64 {
340 (leg.min(hypotenuse) / hypotenuse).asin().to_degrees()
341}
342
343#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, Display, FromStr)]
345#[serde(rename_all = "lowercase")]
346#[display(style = "lowercase")]
347pub enum Primitive {
348 Bool,
350 Number,
352 String,
354 Uuid,
356}