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