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};
31
32use microcad_core::BooleanOp;
33
34use crate::{
35 diag::WriteToFile,
36 rc::RcMut,
37 render::{ComputedHash, HashId, RenderOutput},
38 src_ref::SrcReferrer,
39 syntax::Identifier,
40 tree_display::*,
41 value::Value,
42};
43
44#[derive(Clone, Deref, DerefMut)]
46pub struct Model(RcMut<ModelInner>);
47
48impl Model {
49 pub fn new(inner: RcMut<ModelInner>) -> Self {
51 Self(inner)
52 }
53
54 pub fn depth(&self) -> usize {
56 self.parents().count()
57 }
58
59 pub fn is_operation(&self) -> bool {
61 self.borrow().element.is_operation()
62 }
63
64 pub fn is_empty(&self) -> bool {
66 self.borrow().is_empty()
67 }
68
69 pub fn is_empty_model(&self) -> bool {
71 let self_ = self.borrow();
72 match self_.element.value {
73 Element::BuiltinWorkpiece(_) | Element::InputPlaceholder => false,
74 _ => self_.is_empty(),
75 }
76 }
77
78 pub fn make_deep_copy(&self) -> Self {
81 let copy = Self(RcMut::new(self.0.borrow().clone_content()));
82 for child in self.borrow().children.iter() {
83 copy.append(child.make_deep_copy());
84 }
85 copy
86 }
87
88 pub fn addr(&self) -> usize {
90 self.0.as_ptr().addr()
91 }
92
93 pub fn is_same_as(&self, other: &Model) -> bool {
95 self.addr() == other.addr()
96 }
97
98 pub fn remove_child(&self, child: &Model) {
100 let mut s = self.0.borrow_mut();
101 s.children.retain(|model| !model.is_same_as(child));
102 }
103
104 pub fn detach(&self) {
106 match self.0.borrow_mut().parent {
107 Some(ref mut parent) => {
108 parent.remove_child(self);
109 }
110 None => return,
111 }
112
113 self.0.borrow_mut().parent = None;
114 }
115
116 pub fn append(&self, model: Model) -> Model {
120 model.borrow_mut().parent = Some(self.clone());
121
122 let mut self_ = self.0.borrow_mut();
123 self_.children.push(model.clone());
124
125 model
126 }
127
128 pub fn append_children(&self, models: Models) -> Self {
132 for model in models.iter() {
133 self.append(model.clone());
134 }
135 self.clone()
136 }
137
138 pub fn boolean_op(self, op: BooleanOp, other: Model) -> Model {
140 assert!(self != other, "lhs and rhs must be distinct.");
141 Models::from(vec![self.clone(), other]).boolean_op(op)
142 }
143
144 pub fn replace_input_placeholders(&self, input_model: &Model) -> Self {
146 self.descendants().for_each(|model| {
147 let mut model_ = model.borrow_mut();
148 if model_.id.is_none() && matches!(model_.element.value, Element::InputPlaceholder) {
149 let mut input_model_ = input_model.borrow_mut();
150 input_model_.parent = Some(self.clone());
151 *model_ = input_model_.clone_content();
152 model_.children = input_model_.children.clone();
153 }
154 });
155 self.clone()
156 }
157
158 pub fn deduce_output_type(&self) -> OutputType {
160 let self_ = self.borrow();
161 let mut output_type = self_.element.output_type();
162 if output_type == OutputType::NotDetermined {
163 let children = &self_.children;
164 output_type = children.deduce_output_type();
165 }
166
167 output_type
168 }
169
170 pub fn render_output_type(&self) -> OutputType {
172 let self_ = self.borrow();
173 match self_.output {
174 Some(RenderOutput::Geometry2D { .. }) => OutputType::Geometry2D,
175 Some(RenderOutput::Geometry3D { .. }) => OutputType::Geometry3D,
176 None => OutputType::InvalidMixed,
177 }
178 }
179
180 pub fn into_group(&self) -> Option<Model> {
185 let children = &self.borrow().children;
186 if children.len() != 1 {
187 return None;
188 }
189
190 children.first().and_then(|n| {
191 if let Element::Group = *n.0.borrow().element {
192 Some(n.clone())
193 } else {
194 None
195 }
196 })
197 }
198}
199
200impl Model {
202 pub fn descendants(&self) -> Descendants {
206 Descendants::new(self.clone())
207 }
208
209 pub fn source_file_descendants(&self) -> SourceFileDescendants {
211 SourceFileDescendants::new(self.clone())
212 }
213
214 pub fn parents(&self) -> Parents {
216 Parents::new(self.clone())
217 }
218
219 pub fn ancestors(&self) -> Ancestors {
221 Ancestors::new(self.clone())
222 }
223
224 pub fn get_property(&self, id: &Identifier) -> Option<Value> {
226 self.borrow().element.get_property(id).cloned()
227 }
228
229 pub fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
231 self.borrow_mut().element.set_property(id, value)
232 }
233
234 pub fn add_property(&self, id: Identifier, value: Value) {
236 self.borrow_mut()
237 .element
238 .add_properties([(id, value)].into_iter().collect())
239 }
240}
241
242impl AttributesAccess for Model {
243 fn get_attributes_by_id(&self, id: &Identifier) -> Vec<Attribute> {
244 self.borrow().attributes.get_attributes_by_id(id)
245 }
246}
247
248impl PartialEq for Model {
249 fn eq(&self, other: &Self) -> bool {
250 self.addr() == other.addr()
251 }
252}
253
254impl SrcReferrer for Model {
255 fn src_ref(&self) -> crate::src_ref::SrcRef {
256 self.borrow().src_ref()
257 }
258}
259
260impl std::fmt::Display for Model {
261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262 write!(
263 f,
264 "{id}{element}{is_root} ->",
265 id = match &self.borrow().id {
266 Some(id) => format!("{id}: "),
267 None => String::new(),
268 },
269 element = *self.borrow().element,
270 is_root = if self.parents().next().is_some() {
271 ""
272 } else {
273 " (root)"
274 }
275 )
276 }
277}
278
279impl std::fmt::Debug for Model {
280 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
281 write!(
282 f,
283 "{}",
284 crate::shorten!(format!(
285 "{id}{element}{is_root} ->",
286 id = match &self.borrow().id {
287 Some(id) => format!("{id:?}: "),
288 None => String::new(),
289 },
290 element = *self.borrow().element,
291 is_root = if self.parents().next().is_some() {
292 ""
293 } else {
294 " (root)"
295 }
296 ))
297 )
298 }
299}
300
301impl TreeDisplay for Model {
302 fn tree_print(
303 &self,
304 f: &mut std::fmt::Formatter,
305 mut tree_state: TreeState,
306 ) -> std::fmt::Result {
307 let signature = if tree_state.debug {
308 format!("{self:?}")
309 } else {
310 self.to_string()
311 };
312 let self_ = self.borrow();
313 if let Some(output) = &self_.output {
314 writeln!(f, "{:tree_state$}{signature} {output}", "",)?;
315 } else {
316 writeln!(f, "{:tree_state$}{signature}", "",)?;
317 }
318 tree_state.indent();
319 if let Some(props) = self_.get_properties() {
320 props.tree_print(f, tree_state)?;
321 }
322 self_.attributes.tree_print(f, tree_state)?;
323 self_.children.tree_print(f, tree_state)
324 }
325}
326
327impl WriteToFile for Model {}
328
329impl std::hash::Hash for Model {
330 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
331 let self_ = self.borrow();
332 self_.element().hash(state);
333 self_.children().for_each(|child| child.hash(state));
334 }
335}
336
337impl ComputedHash for Model {
338 fn computed_hash(&self) -> HashId {
339 let self_ = self.borrow();
340 self_.output().computed_hash()
341 }
342}