Skip to main content

microcad_lang/model/
inner.rs

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