microcad_lang/model/
inner.rs

1// Copyright © 2025 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/// Render state of the model.
11pub enum ModelRenderState {
12    /// The model has not been rendered.
13    /// Model output is [`None`].
14    Pending,
15    /// The model has been pre-rendered via [`Model::pre-render`]
16    /// Model output is [`Some`], but there is no geometry.
17    Preparing,
18    /// Rendering is completed.
19    Complete,
20}
21
22/// The actual model contents
23#[derive(custom_debug::Debug, Default)]
24pub struct ModelInner {
25    /// Optional id.
26    ///
27    /// The id is set when the model was created by an assignment: `a = Cube(50mm)`.
28    pub id: Option<Identifier>,
29    /// Parent object.
30    #[debug(skip)]
31    pub parent: Option<Model>,
32    /// Children of the model.
33    pub children: Models,
34    /// All models that have been created by an assignment.
35    pub assignments: FxHashMap<Identifier, Model>,
36    /// Element of the model with [SrcRef].
37    pub element: Refer<Element>,
38    /// Attributes used for export.
39    pub attributes: Attributes,
40    /// The output type of the this model.
41    pub output: Option<RenderOutput>,
42}
43
44impl ModelInner {
45    /// Create a new [`ModelInner`] with a specific element.
46    pub fn new(element: Element, src_ref: SrcRef) -> Self {
47        Self {
48            element: Refer::new(element, src_ref),
49            ..Default::default()
50        }
51    }
52
53    /// Return render state of the model.
54    pub fn render_state(&self) -> ModelRenderState {
55        match &self.output {
56            Some(output) => match output.geometry {
57                Some(_) => ModelRenderState::Complete,
58                None => ModelRenderState::Preparing,
59            },
60            None => ModelRenderState::Pending,
61        }
62    }
63
64    /// Clone only the content of this model without children and parent.
65    pub fn clone_content(&self) -> Self {
66        Self {
67            id: self.id.clone(),
68            parent: None,
69            element: self.element.clone(),
70            attributes: self.attributes.clone(),
71            assignments: self.assignments.clone(),
72            output: self.output.clone(),
73            ..Default::default()
74        }
75    }
76
77    /// Return iterator of children.s
78    pub fn children(&self) -> std::slice::Iter<'_, Model> {
79        self.children.iter()
80    }
81
82    /// Return if ,model has no children.
83    pub fn is_empty(&self) -> bool {
84        self.children.is_empty()
85    }
86
87    /// Read-only access to the element of this model.
88    pub fn element(&self) -> &Element {
89        &self.element
90    }
91
92    /// Read-only access to the attributes of this model.
93    pub fn attributes(&self) -> &Attributes {
94        &self.attributes
95    }
96
97    /// Returns the render output, panics if there is no render output.
98    pub fn output(&self) -> &RenderOutput {
99        self.output
100            .as_ref()
101            .expect("Render output. You have to pre-render() and render() the model first.")
102    }
103
104    /// Returns the mutable render output, panics if there is no render output.
105    pub fn output_mut(&mut self) -> &mut RenderOutput {
106        self.output
107            .as_mut()
108            .expect("Render output. You have to pre-render() and render() the model first.")
109    }
110}
111
112impl PropertiesAccess for ModelInner {
113    fn get_property(&self, id: &Identifier) -> Option<&Value> {
114        self.element.get_property(id)
115    }
116
117    fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
118        self.element.set_property(id, value)
119    }
120
121    fn get_properties(&self) -> Option<&Properties> {
122        self.element.get_properties()
123    }
124
125    fn add_properties(&mut self, props: Properties) {
126        self.element.add_properties(props);
127    }
128}
129
130impl SrcReferrer for ModelInner {
131    fn src_ref(&self) -> SrcRef {
132        self.element.src_ref.clone()
133    }
134}