microcad_lang/model/
mod.rs1pub mod attribute;
7pub mod builder;
8pub mod creator;
9pub mod element;
10mod inner;
11pub mod iter;
12pub mod models;
13pub mod operation;
14pub mod output_type;
15pub mod properties;
16pub mod workpiece;
17
18pub use attribute::*;
19pub use builder::*;
20pub use creator::*;
21pub use element::*;
22pub use inner::*;
23pub use iter::*;
24pub use models::*;
25pub use operation::*;
26pub use output_type::*;
27pub use properties::*;
28pub use workpiece::*;
29
30use derive_more::{Deref, DerefMut};
31use microcad_core::{
32 BooleanOp, Integer,
33 hash::{ComputedHash, HashId},
34};
35use microcad_lang_base::{
36 Identifier, RcMut, SrcRef, SrcReferrer, TreeDisplay, TreeState, WriteToFile,
37};
38
39use crate::{lower::ir::WorkbenchKind, value::Value};
40
41#[derive(Clone, Deref, DerefMut)]
43pub struct Model(RcMut<ModelInner>);
44
45impl Model {
46 pub fn new(inner: RcMut<ModelInner>) -> Self {
48 Self(inner)
49 }
50
51 pub fn is_empty(&self) -> bool {
53 self.borrow().is_empty()
54 }
55
56 pub fn has_no_output(&self) -> bool {
58 let self_ = self.borrow();
59 match self_.element.value {
60 Element::BuiltinWorkpiece(_) | Element::InputPlaceholder => false,
61 _ => self_.is_empty(),
62 }
63 }
64
65 pub fn make_deep_copy(&self) -> Self {
67 let copy = Self(RcMut::new(self.0.borrow().clone_content()));
68 for child in self.borrow().children.iter() {
69 copy.append(child.make_deep_copy());
70 }
71 copy
72 }
73
74 pub fn addr(&self) -> usize {
76 self.0.as_ptr().addr()
77 }
78
79 pub fn append(&self, model: Model) -> Model {
83 model.borrow_mut().parent = Some(self.clone());
84
85 let mut self_ = self.0.borrow_mut();
86 self_.children.push(model.clone());
87
88 model
89 }
90
91 pub fn append_children(&self, models: Models) -> Self {
95 for model in models.iter() {
96 self.append(model.clone());
97 }
98 self.clone()
99 }
100
101 pub fn boolean_op(self, op: BooleanOp, other: Model) -> Model {
103 assert!(self != other, "lhs and rhs must be distinct.");
104 Models::from(vec![self.clone(), other]).boolean_op(op)
105 }
106
107 pub fn multiply(&self, n: Integer) -> Vec<Model> {
109 (0..n).map(|_| self.make_deep_copy()).collect()
110 }
111
112 pub fn replace_input_placeholders(&self, input_model: &Model) -> Self {
114 self.descendants().for_each(|model| {
115 let mut model_ = model.borrow_mut();
116 if model_.id.is_none() && matches!(model_.element.value, Element::InputPlaceholder) {
117 let input_model_ = input_model.borrow_mut();
118 *model_ = input_model_.clone_content();
119 model_.parent = Some(self.clone());
120 model_.children = input_model_.children.clone();
121 }
122 });
123 self.clone()
124 }
125
126 pub fn deduce_output_type(&self) -> OutputType {
128 let self_ = self.borrow();
129 let mut output_type = self_.element.output_type();
130 if output_type == OutputType::NotDetermined {
131 let children = &self_.children;
132 output_type = children.deduce_output_type();
133 }
134
135 output_type
136 }
137
138 pub fn render_output_type(&self) -> OutputType {
140 let self_ = self.borrow();
141 self_
142 .output
143 .as_ref()
144 .map(|output| output.output_type)
145 .unwrap_or(OutputType::InvalidMixed)
146 }
147
148 pub fn into_group(&self) -> Option<Model> {
153 self.borrow()
154 .children
155 .single_model()
156 .filter(|model| matches!(model.borrow().element.value, Element::Group))
157 }
158
159 pub fn set_id(&self, id: Identifier) {
163 self.borrow_mut().id = Some(id);
164 }
165}
166
167impl Model {
169 pub fn descendants(&self) -> Descendants {
173 Descendants::new(self.clone())
174 }
175
176 pub fn multiplicity_descendants(&self) -> MultiplicityDescendants {
178 MultiplicityDescendants::new(self.clone())
179 }
180
181 pub fn source_file_descendants(&self) -> SourceFileDescendants {
183 SourceFileDescendants::new(self.clone())
184 }
185
186 pub fn parents(&self) -> Parents {
188 Parents::new(self.clone())
189 }
190
191 pub fn ancestors(&self) -> Ancestors {
193 Ancestors::new(self.clone())
194 }
195
196 pub fn get_property(&self, id: &Identifier) -> Option<Value> {
198 self.borrow().element.get_property(id).cloned()
199 }
200
201 pub fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
203 self.borrow_mut().element.set_property(id, value)
204 }
205
206 pub fn add_property(&self, id: Identifier, value: Value) {
208 self.borrow_mut()
209 .element
210 .add_properties([(id, value)].into_iter().collect())
211 }
212}
213
214impl AttributesAccess for Model {
215 fn get_attributes_by_id(&self, id: &Identifier) -> Vec<Attribute> {
216 self.borrow().attributes.get_attributes_by_id(id)
217 }
218}
219
220impl PartialEq for Model {
221 fn eq(&self, other: &Self) -> bool {
222 self.addr() == other.addr()
223 }
224}
225
226impl SrcReferrer for Model {
227 fn src_ref(&self) -> SrcRef {
228 self.borrow().src_ref()
229 }
230}
231
232impl std::fmt::Display for Model {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 write!(
235 f,
236 "{id}{element}{is_root} ->",
237 id = match &self.borrow().id {
238 Some(id) => format!("{id}: "),
239 None => String::new(),
240 },
241 element = *self.borrow().element,
242 is_root = if self.parents().next().is_some() {
243 ""
244 } else {
245 " (root)"
246 }
247 )
248 }
249}
250
251impl std::fmt::Debug for Model {
252 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253 write!(
254 f,
255 "{}",
256 microcad_lang_base::shorten(
257 &format!(
258 "{id}{element}{is_root} ->",
259 id = match &self.borrow().id {
260 Some(id) => format!("{id:?}: "),
261 None => String::new(),
262 },
263 element = *self.borrow().element,
264 is_root = if self.parents().next().is_some() {
265 ""
266 } else {
267 " (root)"
268 }
269 ),
270 140
271 )
272 )
273 }
274}
275
276impl TreeDisplay for Model {
277 fn tree_print(
278 &self,
279 f: &mut std::fmt::Formatter,
280 mut tree_state: TreeState,
281 ) -> std::fmt::Result {
282 let signature = if tree_state.debug {
283 format!("{self:?}")
284 } else {
285 self.to_string()
286 };
287 let self_ = self.borrow();
288 if let Some(output) = &self_.output {
289 writeln!(f, "{:tree_state$}{signature} {output}", "",)?;
290 } else {
291 writeln!(f, "{:tree_state$}{signature}", "",)?;
292 }
293 tree_state.indent();
294 if let Some(props) = self_.get_properties() {
295 props.tree_print(f, tree_state)?;
296 }
297 self_.attributes.tree_print(f, tree_state)?;
298 self_.children.tree_print(f, tree_state)
299 }
300}
301
302impl WriteToFile for Model {}
303
304impl std::hash::Hash for Model {
305 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
306 let self_ = self.borrow();
307 self_.element().hash(state);
308 self_.children().for_each(|child| child.hash(state));
309 }
310}
311
312impl ComputedHash for Model {
313 fn computed_hash(&self) -> HashId {
314 let self_ = self.borrow();
315 self_.output().computed_hash()
316 }
317}