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
26pub enum BuiltinWorkpieceOutput {
28 Primitive2D(Box<dyn RenderWithContext<Geometry2DOutput>>),
30 Primitive3D(Box<dyn RenderWithContext<Geometry3DOutput>>),
32 Transform(AffineTransform),
34 Operation(Box<dyn Operation>),
36}
37
38pub type BuiltinWorkpieceFn = dyn Fn(&Tuple) -> RenderResult<BuiltinWorkpieceOutput>;
40
41#[derive(Clone, Debug)]
43pub struct BuiltinWorkpiece {
44 pub kind: BuiltinWorkbenchKind,
46 pub output_type: OutputType,
48 pub creator: Hashed<Creator>,
50 #[debug(skip)]
52 pub f: &'static BuiltinWorkpieceFn,
53}
54
55impl BuiltinWorkpiece {
56 pub fn call(&self) -> RenderResult<BuiltinWorkpieceOutput> {
58 (self.f)(&self.creator.arguments)
59 }
60}
61
62impl std::fmt::Display for BuiltinWorkpiece {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 write!(
65 f,
66 "{kind} {creator}",
67 kind = self.kind,
68 creator = *self.creator,
69 )
70 }
71}
72
73impl ComputedHash for BuiltinWorkpiece {
74 fn computed_hash(&self) -> crate::render::HashId {
75 self.creator.computed_hash()
76 }
77}
78
79pub trait BuiltinWorkbenchDefinition {
81 fn id() -> &'static str;
83
84 fn kind() -> BuiltinWorkbenchKind;
86
87 fn help() -> Option<&'static str> {
89 None
90 }
91
92 fn output_type() -> OutputType {
94 OutputType::NotDetermined
95 }
96
97 fn workpiece_function() -> &'static BuiltinWorkpieceFn;
99
100 fn workpiece(creator: Creator) -> BuiltinWorkpiece {
102 BuiltinWorkpiece {
103 kind: Self::kind(),
104 output_type: Self::output_type(),
105 creator: Hashed::new(creator),
106 f: Self::workpiece_function(),
107 }
108 }
109
110 fn model(creator: Creator) -> Model {
112 let workpiece = Self::workpiece(creator);
113 let model = ModelBuilder::new(Element::BuiltinWorkpiece(workpiece), SrcRef(None)).build();
114
115 if Self::kind() == BuiltinWorkbenchKind::Operation
118 || Self::kind() == BuiltinWorkbenchKind::Transform
119 {
120 model.append(ModelBuilder::new(Element::InputPlaceholder, SrcRef(None)).build());
121 }
122 model
123 }
124
125 fn function() -> &'static BuiltinFn {
127 &|params, args, context| {
128 log::trace!(
129 "Built-in workbench {call} {id:?}({args})",
130 call = crate::mark!(CALL),
131 id = Self::id()
132 );
133 Ok(Value::Model(
134 ArgumentMatch::find_multi_match(args, params)?
135 .iter()
136 .map(|tuple| Self::model(Creator::new(context.current_symbol(), tuple.clone())))
137 .collect::<Models>()
138 .to_multiplicity(SrcRef(None)),
139 ))
140 }
141 }
142
143 fn doc() -> Option<DocBlock> {
145 Self::help().map(DocBlock::new_builtin)
146 }
147
148 fn parameters() -> ParameterValueList {
150 ParameterValueList::default()
151 }
152
153 fn symbol() -> Symbol {
155 Symbol::new_builtin(Builtin {
156 id: Identifier::no_ref(Self::id()),
157 parameters: Self::parameters(),
158 kind: BuiltinKind::Workbench(Self::kind()),
159 f: Self::function(),
160 doc: Self::doc(),
161 })
162 }
163}