Skip to main content

microcad_lang/model/
inner.rs

1// Copyright © 2025-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Model
5
6use microcad_lang_base::Refer;
7use rustc_hash::FxHashMap;
8
9use crate::{model::*, render::*, syntax::*};
10
11/// The actual model contents
12#[derive(custom_debug::Debug, Default)]
13pub struct ModelInner {
14    /// Optional id.
15    ///
16    /// The id is set when the model was created by an assignment: `a = Cube(50mm)`.
17    pub id: Option<Identifier>,
18    /// Parent object.
19    #[debug(skip)]
20    pub parent: Option<Model>,
21    /// Children of the model.
22    pub children: Models,
23    /// All models that have been created by an assignment.
24    pub assignments: FxHashMap<Identifier, Model>,
25    /// Element of the model with [SrcRef].
26    pub element: Refer<Element>,
27    /// Attributes used for export.
28    pub attributes: Attributes,
29    /// The output type of the this model.
30    pub output: Option<RenderOutput>,
31}
32
33impl ModelInner {
34    /// Create a new [`ModelInner`] with a specific element.
35    pub fn new(element: Element, src_ref: SrcRef) -> Self {
36        Self {
37            element: Refer::new(element, src_ref),
38            ..Default::default()
39        }
40    }
41
42    /// Clone only the content of this model without children and parent.
43    pub fn clone_content(&self) -> Self {
44        Self {
45            id: self.id.clone(),
46            parent: None,
47            element: self.element.clone(),
48            attributes: self.attributes.clone(),
49            assignments: self.assignments.clone(),
50            output: self.output.clone(),
51            ..Default::default()
52        }
53    }
54
55    /// Return iterator of children.s
56    pub fn children(&self) -> std::slice::Iter<'_, Model> {
57        self.children.iter()
58    }
59
60    /// Return if ,model has no children.
61    pub fn is_empty(&self) -> bool {
62        self.children.is_empty()
63    }
64
65    /// Read-only access to the element of this model.
66    pub fn element(&self) -> &Element {
67        &self.element
68    }
69
70    /// Read-only access to the attributes of this model.
71    pub fn attributes(&self) -> &Attributes {
72        &self.attributes
73    }
74
75    /// Returns the render output, panics if there is no render output.
76    pub fn output(&self) -> &RenderOutput {
77        self.output
78            .as_ref()
79            .expect("Render output. You have to pre-render() and render() the model first.")
80    }
81
82    /// Returns the mutable render output, panics if there is no render output.
83    pub fn output_mut(&mut self) -> &mut RenderOutput {
84        self.output
85            .as_mut()
86            .expect("Render output. You have to pre-render() and render() the model first.")
87    }
88}
89
90impl PropertiesAccess for ModelInner {
91    fn get_property(&self, id: &Identifier) -> Option<&Value> {
92        self.element.get_property(id)
93    }
94
95    fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
96        self.element.set_property(id, value)
97    }
98
99    fn get_properties(&self) -> Option<&Properties> {
100        self.element.get_properties()
101    }
102
103    fn add_properties(&mut self, props: Properties) {
104        self.element.add_properties(props);
105    }
106}
107
108impl SrcReferrer for ModelInner {
109    fn src_ref(&self) -> SrcRef {
110        self.element.src_ref.clone()
111    }
112}