microcad_lang/builtin/
workpiece.rs1use custom_debug::Debug;
7use strum::Display;
8
9use crate::{
10 builtin::*, eval::*, model::*, render::*, resolve::*, src_ref::*, syntax::*, value::*,
11};
12
13#[derive(Debug, Clone, Display, PartialEq)]
15pub enum BuiltinWorkbenchKind {
16 Primitive2D,
18 Primitive3D,
20 Transform,
22 Operation,
24}
25
26impl BuiltinWorkbenchKind {
27
28 pub fn as_str(&self) -> &'static str {
30 match self {
31 BuiltinWorkbenchKind::Primitive2D => "primitive-2d",
32 BuiltinWorkbenchKind::Primitive3D => "primitive-3d",
33 BuiltinWorkbenchKind::Transform => "transform",
34 BuiltinWorkbenchKind::Operation => "operator",
35 }
36 }
37}
38
39pub enum BuiltinWorkpieceOutput {
41 Primitive2D(Box<dyn RenderWithContext<Geometry2DOutput>>),
43 Primitive3D(Box<dyn RenderWithContext<Geometry3DOutput>>),
45 Transform(AffineTransform),
47 Operation(Box<dyn Operation>),
49}
50
51pub type BuiltinWorkpieceFn = dyn Fn(&Tuple) -> RenderResult<BuiltinWorkpieceOutput>;
53
54#[derive(Clone, Debug)]
56pub struct BuiltinWorkpiece {
57 pub kind: BuiltinWorkbenchKind,
59 pub output_type: OutputType,
61 pub creator: Hashed<Creator>,
63 #[debug(skip)]
65 pub f: &'static BuiltinWorkpieceFn,
66}
67
68impl BuiltinWorkpiece {
69 pub fn call(&self) -> RenderResult<BuiltinWorkpieceOutput> {
71 (self.f)(&self.creator.arguments)
72 }
73}
74
75impl std::fmt::Display for BuiltinWorkpiece {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 write!(
78 f,
79 "{kind} {creator}",
80 kind = self.kind,
81 creator = *self.creator,
82 )
83 }
84}
85
86impl ComputedHash for BuiltinWorkpiece {
87 fn computed_hash(&self) -> crate::render::HashId {
88 self.creator.computed_hash()
89 }
90}
91
92pub trait BuiltinWorkbenchDefinition {
94 fn id() -> &'static str;
96
97 fn kind() -> BuiltinWorkbenchKind;
99
100 fn help() -> Option<&'static str> {
102 None
103 }
104
105 fn output_type() -> OutputType {
107 OutputType::NotDetermined
108 }
109
110 fn workpiece_function() -> &'static BuiltinWorkpieceFn;
112
113 fn workpiece(creator: Creator) -> BuiltinWorkpiece {
115 BuiltinWorkpiece {
116 kind: Self::kind(),
117 output_type: Self::output_type(),
118 creator: Hashed::new(creator),
119 f: Self::workpiece_function(),
120 }
121 }
122
123 fn model(creator: Creator) -> Model {
125 let workpiece = Self::workpiece(creator);
126 let model = ModelBuilder::new(Element::BuiltinWorkpiece(workpiece), SrcRef(None)).build();
127
128 if Self::kind() == BuiltinWorkbenchKind::Operation
131 || Self::kind() == BuiltinWorkbenchKind::Transform
132 {
133 model.append(ModelBuilder::new(Element::InputPlaceholder, SrcRef(None)).build());
134 }
135 model
136 }
137
138 fn function() -> &'static BuiltinFn {
140 &|params, args, context| {
141 log::trace!(
142 "Built-in workbench {call} {id:?}({args})",
143 call = crate::mark!(CALL),
144 id = Self::id()
145 );
146 Ok(Value::Model(
147 ArgumentMatch::find_multi_match(args, params)?
148 .args
149 .iter()
150 .map(|tuple| Self::model(Creator::new(context.current_symbol(), tuple.clone())))
151 .collect::<Models>()
152 .to_multiplicity(SrcRef(None)),
153 ))
154 }
155 }
156
157 fn doc() -> Option<DocBlock> {
159 Self::help().map(DocBlock::new_builtin)
160 }
161
162 fn parameters() -> ParameterValueList {
164 ParameterValueList::default()
165 }
166
167 fn symbol() -> Symbol {
169 Symbol::new_builtin(Builtin {
170 id: Identifier::no_ref(Self::id()),
171 parameters: Self::parameters(),
172 kind: BuiltinKind::Workbench(Self::kind()),
173 f: Self::function(),
174 doc: Self::doc(),
175 })
176 }
177}