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::{RcMut, SrcRef, SrcReferrer, TreeDisplay, TreeState, WriteToFile};
36
37use crate::{syntax::Identifier, value::Value};
38
39#[derive(Clone, Deref, DerefMut)]
41pub struct Model(RcMut<ModelInner>);
42
43impl Model {
44 pub fn new(inner: RcMut<ModelInner>) -> Self {
46 Self(inner)
47 }
48
49 pub fn is_empty(&self) -> bool {
51 self.borrow().is_empty()
52 }
53
54 pub fn has_no_output(&self) -> bool {
56 let self_ = self.borrow();
57 match self_.element.value {
58 Element::BuiltinWorkpiece(_) | Element::InputPlaceholder => false,
59 _ => self_.is_empty(),
60 }
61 }
62
63 pub fn make_deep_copy(&self) -> Self {
65 let copy = Self(RcMut::new(self.0.borrow().clone_content()));
66 for child in self.borrow().children.iter() {
67 copy.append(child.make_deep_copy());
68 }
69 copy
70 }
71
72 pub fn addr(&self) -> usize {
74 self.0.as_ptr().addr()
75 }
76
77 pub fn append(&self, model: Model) -> Model {
81 model.borrow_mut().parent = Some(self.clone());
82
83 let mut self_ = self.0.borrow_mut();
84 self_.children.push(model.clone());
85
86 model
87 }
88
89 pub fn append_children(&self, models: Models) -> Self {
93 for model in models.iter() {
94 self.append(model.clone());
95 }
96 self.clone()
97 }
98
99 pub fn boolean_op(self, op: BooleanOp, other: Model) -> Model {
101 assert!(self != other, "lhs and rhs must be distinct.");
102 Models::from(vec![self.clone(), other]).boolean_op(op)
103 }
104
105 pub fn multiply(&self, n: Integer) -> Vec<Model> {
107 (0..n).map(|_| self.make_deep_copy()).collect()
108 }
109
110 pub fn replace_input_placeholders(&self, input_model: &Model) -> Self {
112 self.descendants().for_each(|model| {
113 let mut model_ = model.borrow_mut();
114 if model_.id.is_none() && matches!(model_.element.value, Element::InputPlaceholder) {
115 let input_model_ = input_model.borrow_mut();
116 *model_ = input_model_.clone_content();
117 model_.parent = Some(self.clone());
118 model_.children = input_model_.children.clone();
119 }
120 });
121 self.clone()
122 }
123
124 pub fn deduce_output_type(&self) -> OutputType {
126 let self_ = self.borrow();
127 let mut output_type = self_.element.output_type();
128 if output_type == OutputType::NotDetermined {
129 let children = &self_.children;
130 output_type = children.deduce_output_type();
131 }
132
133 output_type
134 }
135
136 pub fn render_output_type(&self) -> OutputType {
138 let self_ = self.borrow();
139 self_
140 .output
141 .as_ref()
142 .map(|output| output.output_type)
143 .unwrap_or(OutputType::InvalidMixed)
144 }
145
146 pub fn into_group(&self) -> Option<Model> {
151 self.borrow()
152 .children
153 .single_model()
154 .filter(|model| matches!(model.borrow().element.value, Element::Group))
155 }
156
157 pub fn set_id(&self, id: Identifier) {
161 self.borrow_mut().id = Some(id);
162 }
163}
164
165impl Model {
167 pub fn descendants(&self) -> Descendants {
171 Descendants::new(self.clone())
172 }
173
174 pub fn multiplicity_descendants(&self) -> MultiplicityDescendants {
176 MultiplicityDescendants::new(self.clone())
177 }
178
179 pub fn source_file_descendants(&self) -> SourceFileDescendants {
181 SourceFileDescendants::new(self.clone())
182 }
183
184 pub fn parents(&self) -> Parents {
186 Parents::new(self.clone())
187 }
188
189 pub fn ancestors(&self) -> Ancestors {
191 Ancestors::new(self.clone())
192 }
193
194 pub fn get_property(&self, id: &Identifier) -> Option<Value> {
196 self.borrow().element.get_property(id).cloned()
197 }
198
199 pub fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
201 self.borrow_mut().element.set_property(id, value)
202 }
203
204 pub fn add_property(&self, id: Identifier, value: Value) {
206 self.borrow_mut()
207 .element
208 .add_properties([(id, value)].into_iter().collect())
209 }
210}
211
212impl AttributesAccess for Model {
213 fn get_attributes_by_id(&self, id: &Identifier) -> Vec<Attribute> {
214 self.borrow().attributes.get_attributes_by_id(id)
215 }
216}
217
218impl PartialEq for Model {
219 fn eq(&self, other: &Self) -> bool {
220 self.addr() == other.addr()
221 }
222}
223
224impl SrcReferrer for Model {
225 fn src_ref(&self) -> SrcRef {
226 self.borrow().src_ref()
227 }
228}
229
230impl std::fmt::Display for Model {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 write!(
233 f,
234 "{id}{element}{is_root} ->",
235 id = match &self.borrow().id {
236 Some(id) => format!("{id}: "),
237 None => String::new(),
238 },
239 element = *self.borrow().element,
240 is_root = if self.parents().next().is_some() {
241 ""
242 } else {
243 " (root)"
244 }
245 )
246 }
247}
248
249impl std::fmt::Debug for Model {
250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251 write!(
252 f,
253 "{}",
254 microcad_lang_base::shorten!(format!(
255 "{id}{element}{is_root} ->",
256 id = match &self.borrow().id {
257 Some(id) => format!("{id:?}: "),
258 None => String::new(),
259 },
260 element = *self.borrow().element,
261 is_root = if self.parents().next().is_some() {
262 ""
263 } else {
264 " (root)"
265 }
266 ))
267 )
268 }
269}
270
271impl TreeDisplay for Model {
272 fn tree_print(
273 &self,
274 f: &mut std::fmt::Formatter,
275 mut tree_state: TreeState,
276 ) -> std::fmt::Result {
277 let signature = if tree_state.debug {
278 format!("{self:?}")
279 } else {
280 self.to_string()
281 };
282 let self_ = self.borrow();
283 if let Some(output) = &self_.output {
284 writeln!(f, "{:tree_state$}{signature} {output}", "",)?;
285 } else {
286 writeln!(f, "{:tree_state$}{signature}", "",)?;
287 }
288 tree_state.indent();
289 if let Some(props) = self_.get_properties() {
290 props.tree_print(f, tree_state)?;
291 }
292 self_.attributes.tree_print(f, tree_state)?;
293 self_.children.tree_print(f, tree_state)
294 }
295}
296
297impl WriteToFile for Model {}
298
299impl std::hash::Hash for Model {
300 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
301 let self_ = self.borrow();
302 self_.element().hash(state);
303 self_.children().for_each(|child| child.hash(state));
304 }
305}
306
307impl ComputedHash for Model {
308 fn computed_hash(&self) -> HashId {
309 let self_ = self.borrow();
310 self_.output().computed_hash()
311 }
312}