microcad_lang/builtin/
workpiece.rs1use custom_debug::Debug;
7use strum::Display;
8
9use crate::{
10 eval::*,
11 model::*,
12 render::{
13 ComputedHash, Geometry2DOutput, Geometry3DOutput, Hashed, RenderResult, RenderWithContext,
14 },
15 resolve::Symbol,
16 src_ref::SrcRef,
17 syntax::*,
18 value::*,
19};
20
21pub type BuiltinFn =
23 dyn Fn(Option<&ParameterValueList>, &ArgumentValueList, &mut EvalContext) -> EvalResult<Value>;
24
25#[derive(Clone)]
27pub struct Builtin {
28 pub id: Identifier,
30
31 pub parameters: Option<ParameterValueList>,
33
34 pub f: &'static BuiltinFn,
36}
37
38impl std::fmt::Debug for Builtin {
39 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
40 write!(f, "__builtin::{}", &self.id)
41 }
42}
43
44impl Builtin {
45 pub fn id(&self) -> Identifier {
47 self.id.clone()
48 }
49}
50
51impl CallTrait for Builtin {
52 fn call(&self, args: &ArgumentValueList, context: &mut EvalContext) -> EvalResult<Value> {
57 (self.f)(self.parameters.as_ref(), args, context)
58 }
59}
60
61#[derive(Debug, Clone, Display)]
63pub enum BuiltinWorkbenchKind {
64 Primitive2D,
66 Primitive3D,
68 Transform,
70 Operation,
72}
73
74pub enum BuiltinWorkpieceOutput {
76 Primitive2D(Box<dyn RenderWithContext<Geometry2DOutput>>),
78 Primitive3D(Box<dyn RenderWithContext<Geometry3DOutput>>),
80 Transform(AffineTransform),
82 Operation(Box<dyn Operation>),
84}
85
86pub type BuiltinWorkpieceFn = dyn Fn(&Tuple) -> RenderResult<BuiltinWorkpieceOutput>;
88
89#[derive(Clone, Debug)]
91pub struct BuiltinWorkpiece {
92 pub kind: BuiltinWorkbenchKind,
94 pub output_type: OutputType,
96 pub creator: Hashed<Creator>,
98 #[debug(skip)]
100 pub f: &'static BuiltinWorkpieceFn,
101}
102
103impl BuiltinWorkpiece {
104 pub fn call(&self) -> RenderResult<BuiltinWorkpieceOutput> {
106 (self.f)(&self.creator.arguments)
107 }
108}
109
110impl std::fmt::Display for BuiltinWorkpiece {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 write!(
113 f,
114 "{kind} {creator}",
115 kind = self.kind,
116 creator = *self.creator,
117 )
118 }
119}
120
121impl ComputedHash for BuiltinWorkpiece {
122 fn computed_hash(&self) -> crate::render::HashId {
123 self.creator.computed_hash()
124 }
125}
126
127pub trait BuiltinWorkbenchDefinition {
129 fn id() -> &'static str;
131
132 fn kind() -> BuiltinWorkbenchKind;
134
135 fn output_type() -> OutputType {
137 OutputType::NotDetermined
138 }
139
140 fn workpiece_function() -> &'static BuiltinWorkpieceFn;
142
143 fn workpiece(creator: Creator) -> BuiltinWorkpiece {
145 BuiltinWorkpiece {
146 kind: Self::kind(),
147 output_type: Self::output_type(),
148 creator: Hashed::new(creator),
149 f: Self::workpiece_function(),
150 }
151 }
152
153 fn model(creator: Creator) -> Model {
155 ModelBuilder::new(
156 Element::BuiltinWorkpiece(Self::workpiece(creator)),
157 SrcRef(None),
158 )
159 .build()
160 }
161
162 fn function() -> &'static BuiltinFn {
164 &|params, args, context| {
165 log::trace!(
166 "Built-in workbench {call} {id:?}({args})",
167 call = crate::mark!(CALL),
168 id = Self::id()
169 );
170 Ok(Value::Model(
171 ArgumentMatch::find_multi_match(
172 args,
173 params.expect("A built-in part must have a parameter list"),
174 )?
175 .iter()
176 .map(|tuple| Self::model(Creator::new(context.current_symbol(), tuple.clone())))
177 .collect::<Models>()
178 .to_multiplicity(SrcRef(None)),
179 ))
180 }
181 }
182
183 fn parameters() -> ParameterValueList {
185 ParameterValueList::default()
186 }
187
188 fn symbol() -> Symbol {
190 Symbol::new_builtin(
191 Identifier::no_ref(Self::id()),
192 Some(Self::parameters()),
193 Self::function(),
194 )
195 }
196}