microcad_lang/model/
mod.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Model tree module
5
6pub 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, Integer};
33
34use crate::{
35    diag::WriteToFile,
36    rc::RcMut,
37    render::{ComputedHash, HashId},
38    src_ref::SrcReferrer,
39    syntax::Identifier,
40    tree_display::*,
41    value::Value,
42};
43
44/// A reference counted, mutable [`Model`].
45#[derive(Clone, Deref, DerefMut)]
46pub struct Model(RcMut<ModelInner>);
47
48impl Model {
49    /// Create new model from inner.
50    pub fn new(inner: RcMut<ModelInner>) -> Self {
51        Self(inner)
52    }
53
54    /// Calculate depth of the model.
55    pub fn depth(&self) -> usize {
56        self.parents().count()
57    }
58
59    /// Return `true`, if model has no children.
60    pub fn is_empty(&self) -> bool {
61        self.borrow().is_empty()
62    }
63
64    /// Return `true`, if model wont produce any output
65    pub fn has_no_output(&self) -> bool {
66        let self_ = self.borrow();
67        match self_.element.value {
68            Element::BuiltinWorkpiece(_) | Element::InputPlaceholder => false,
69            _ => self_.is_empty(),
70        }
71    }
72
73    /// Make a deep copy if this model.
74    /// TODO: isn't this a Clone?
75    pub fn make_deep_copy(&self) -> Self {
76        let copy = Self(RcMut::new(self.0.borrow().clone_content()));
77        for child in self.borrow().children.iter() {
78            copy.append(child.make_deep_copy());
79        }
80        copy
81    }
82
83    /// Return address of this model.
84    pub fn addr(&self) -> usize {
85        self.0.as_ptr().addr()
86    }
87
88    /// Check if `other` is and `self` have the same address.
89    pub fn is_same_as(&self, other: &Model) -> bool {
90        self.addr() == other.addr()
91    }
92
93    /// Remove child from this model.
94    pub fn remove_child(&self, child: &Model) {
95        let mut s = self.0.borrow_mut();
96        s.children.retain(|model| !model.is_same_as(child));
97    }
98
99    /// Append a single model as child.
100    ///
101    /// Also tries to set the output type if it has not been determined yet.
102    pub fn append(&self, model: Model) -> Model {
103        model.borrow_mut().parent = Some(self.clone());
104
105        let mut self_ = self.0.borrow_mut();
106        self_.children.push(model.clone());
107
108        model
109    }
110
111    /// Append multiple models as children.
112    ///
113    /// Return self.
114    pub fn append_children(&self, models: Models) -> Self {
115        for model in models.iter() {
116            self.append(model.clone());
117        }
118        self.clone()
119    }
120
121    /// Short cut to generate boolean operator as binary operation with two models.
122    pub fn boolean_op(self, op: BooleanOp, other: Model) -> Model {
123        assert!(self != other, "lhs and rhs must be distinct.");
124        Models::from(vec![self.clone(), other]).boolean_op(op)
125    }
126
127    /// Multiply a model n times.
128    pub fn multiply(&self, n: Integer) -> Vec<Model> {
129        (0..n).map(|_| self.make_deep_copy()).collect()
130    }
131
132    /// Replace each input placeholder with copies of `input_model`.
133    pub fn replace_input_placeholders(&self, input_model: &Model) -> Self {
134        self.descendants().for_each(|model| {
135            let mut model_ = model.borrow_mut();
136            if model_.id.is_none() && matches!(model_.element.value, Element::InputPlaceholder) {
137                let input_model_ = input_model.borrow_mut();
138                *model_ = input_model_.clone_content();
139                model_.parent = Some(self.clone());
140                model_.children = input_model_.children.clone();
141            }
142        });
143        self.clone()
144    }
145
146    /// Deduce output type from children and set it and return it.
147    pub fn deduce_output_type(&self) -> OutputType {
148        let self_ = self.borrow();
149        let mut output_type = self_.element.output_type();
150        if output_type == OutputType::NotDetermined {
151            let children = &self_.children;
152            output_type = children.deduce_output_type();
153        }
154
155        output_type
156    }
157
158    /// Get render output type. Expects a render output.
159    pub fn render_output_type(&self) -> OutputType {
160        let self_ = self.borrow();
161        self_
162            .output
163            .as_ref()
164            .map(|output| output.output_type)
165            .unwrap_or(OutputType::InvalidMixed)
166    }
167
168    /// Return inner group if this model only contains a group as single child.
169    ///
170    /// This function is used when we evaluate operations like `subtract() {}` or `hull() {}`.
171    /// When evaluating these operations, we want to iterate over the group's children.
172    pub fn into_group(&self) -> Option<Model> {
173        self.borrow()
174            .children
175            .single_model()
176            .filter(|model| matches!(model.borrow().element.value, Element::Group))
177    }
178
179    /// Set the id of a model. This happens if the model was created by an assignment.
180    ///
181    /// For example, the assignment statement `a = Circle(4mm)` will result in a model with id `a`.
182    pub fn set_id(&self, id: Identifier) {
183        self.borrow_mut().id = Some(id);
184    }
185}
186
187/// Iterator methods.
188impl Model {
189    /// Returns an iterator of models to this model and its unnamed descendants, in tree order.
190    ///
191    /// Includes the current model.
192    pub fn descendants(&self) -> Descendants {
193        Descendants::new(self.clone())
194    }
195
196    /// An iterator that descends to multiplicity nodes.
197    pub fn multiplicity_descendants(&self) -> MultiplicityDescendants {
198        MultiplicityDescendants::new(self.clone())
199    }
200
201    /// Returns an iterator of models that belong to the same source file as this one
202    pub fn source_file_descendants(&self) -> SourceFileDescendants {
203        SourceFileDescendants::new(self.clone())
204    }
205
206    /// Parents iterator.
207    pub fn parents(&self) -> Parents {
208        Parents::new(self.clone())
209    }
210
211    /// Ancestors iterator.
212    pub fn ancestors(&self) -> Ancestors {
213        Ancestors::new(self.clone())
214    }
215
216    /// Get a property from this model.
217    pub fn get_property(&self, id: &Identifier) -> Option<Value> {
218        self.borrow().element.get_property(id).cloned()
219    }
220
221    /// Set a property in this model.
222    pub fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
223        self.borrow_mut().element.set_property(id, value)
224    }
225
226    /// Add a new property to the model.
227    pub fn add_property(&self, id: Identifier, value: Value) {
228        self.borrow_mut()
229            .element
230            .add_properties([(id, value)].into_iter().collect())
231    }
232}
233
234impl AttributesAccess for Model {
235    fn get_attributes_by_id(&self, id: &Identifier) -> Vec<Attribute> {
236        self.borrow().attributes.get_attributes_by_id(id)
237    }
238}
239
240impl PartialEq for Model {
241    fn eq(&self, other: &Self) -> bool {
242        self.addr() == other.addr()
243    }
244}
245
246impl SrcReferrer for Model {
247    fn src_ref(&self) -> crate::src_ref::SrcRef {
248        self.borrow().src_ref()
249    }
250}
251
252impl std::fmt::Display for Model {
253    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254        write!(
255            f,
256            "{id}{element}{is_root} ->",
257            id = match &self.borrow().id {
258                Some(id) => format!("{id}: "),
259                None => String::new(),
260            },
261            element = *self.borrow().element,
262            is_root = if self.parents().next().is_some() {
263                ""
264            } else {
265                " (root)"
266            }
267        )
268    }
269}
270
271impl std::fmt::Debug for Model {
272    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273        write!(
274            f,
275            "{}",
276            crate::shorten!(format!(
277                "{id}{element}{is_root} ->",
278                id = match &self.borrow().id {
279                    Some(id) => format!("{id:?}: "),
280                    None => String::new(),
281                },
282                element = *self.borrow().element,
283                is_root = if self.parents().next().is_some() {
284                    ""
285                } else {
286                    " (root)"
287                }
288            ))
289        )
290    }
291}
292
293impl TreeDisplay for Model {
294    fn tree_print(
295        &self,
296        f: &mut std::fmt::Formatter,
297        mut tree_state: TreeState,
298    ) -> std::fmt::Result {
299        let signature = if tree_state.debug {
300            format!("{self:?}")
301        } else {
302            self.to_string()
303        };
304        let self_ = self.borrow();
305        if let Some(output) = &self_.output {
306            writeln!(f, "{:tree_state$}{signature} {output}", "",)?;
307        } else {
308            writeln!(f, "{:tree_state$}{signature}", "",)?;
309        }
310        tree_state.indent();
311        if let Some(props) = self_.get_properties() {
312            props.tree_print(f, tree_state)?;
313        }
314        self_.attributes.tree_print(f, tree_state)?;
315        self_.children.tree_print(f, tree_state)
316    }
317}
318
319impl WriteToFile for Model {}
320
321impl std::hash::Hash for Model {
322    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
323        let self_ = self.borrow();
324        self_.element().hash(state);
325        self_.children().for_each(|child| child.hash(state));
326    }
327}
328
329impl ComputedHash for Model {
330    fn computed_hash(&self) -> HashId {
331        let self_ = self.borrow();
332        self_.output().computed_hash()
333    }
334}