Skip to main content

microcad_lang/model/
element.rs

1// Copyright © 2025-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Element of a [`Model`].
5
6use crate::{builtin::*, model::*, value::*};
7use strum::IntoStaticStr;
8
9/// An element defines the entity of a [`Model`].
10#[derive(Clone, IntoStaticStr, Debug, Default)]
11pub enum Element {
12    #[default]
13    /// A group element is created by a body `{}`.
14    Group,
15
16    /// A workpiece that holds properties.
17    ///
18    /// A workpiece is created by workbenches.
19    Workpiece(Workpiece),
20
21    /// A built-in workpiece.
22    ///
23    /// A workpiece is created by workbenches.
24    BuiltinWorkpiece(BuiltinWorkpiece),
25
26    /// Multiplicity.
27    Multiplicity,
28
29    /// Created from `@input` marker. Will never be part of the final model.
30    InputPlaceholder,
31}
32
33impl Element {
34    /// Creator.
35    pub fn creator(&self) -> Option<&Creator> {
36        match self {
37            Element::Workpiece(workpiece) => Some(&workpiece.creator),
38            Element::BuiltinWorkpiece(builtin_workpiece) => Some(&builtin_workpiece.creator),
39            _ => None,
40        }
41    }
42
43    /// Get output type of element.
44    pub fn output_type(&self) -> OutputType {
45        match self {
46            Element::Workpiece(workpiece) => workpiece.kind.into(),
47            Element::BuiltinWorkpiece(builtin_workpiece) => match builtin_workpiece.kind {
48                BuiltinWorkbenchKind::Primitive2D => OutputType::Geometry2D,
49                BuiltinWorkbenchKind::Primitive3D => OutputType::Geometry3D,
50                BuiltinWorkbenchKind::Transform | BuiltinWorkbenchKind::Operation => {
51                    builtin_workpiece.output_type
52                }
53            },
54            Element::Group | Element::Multiplicity | Element::InputPlaceholder => {
55                OutputType::NotDetermined
56            }
57        }
58    }
59}
60
61impl std::fmt::Display for Element {
62    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
63        let name: &'static str = self.into();
64        match &self {
65            Element::Workpiece(workpiece) => write!(f, "{workpiece}"),
66            Element::BuiltinWorkpiece(builtin_workpiece) => write!(f, "{builtin_workpiece}"),
67            _ => write!(f, "{name}"),
68        }
69    }
70}
71
72impl std::hash::Hash for Element {
73    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
74        match self {
75            Element::Group => std::mem::discriminant(&Element::Group).hash(state),
76            Element::Multiplicity => std::mem::discriminant(&Element::Multiplicity).hash(state),
77            Element::InputPlaceholder => {
78                std::mem::discriminant(&Element::InputPlaceholder).hash(state)
79            }
80            Element::Workpiece(workpiece) => workpiece.computed_hash().hash(state),
81            Element::BuiltinWorkpiece(builtin_workpiece) => {
82                builtin_workpiece.computed_hash().hash(state)
83            }
84        }
85    }
86}
87
88impl PropertiesAccess for Element {
89    fn get_property(&self, id: &Identifier) -> Option<&Value> {
90        match self {
91            Self::Workpiece(workpiece) => workpiece.get_property(id),
92            _ => unreachable!("not a workpiece element"),
93        }
94    }
95
96    fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
97        match self {
98            Self::Workpiece(workpiece) => workpiece.set_property(id, value),
99            _ => unreachable!("not a workpiece element"),
100        }
101    }
102
103    fn get_properties(&self) -> Option<&Properties> {
104        match self {
105            Self::Workpiece(workpiece) => workpiece.get_properties(),
106            _ => None,
107        }
108    }
109
110    fn add_properties(&mut self, props: Properties) {
111        match self {
112            Self::Workpiece(workpiece) => {
113                workpiece.add_properties(props);
114            }
115            _ => unreachable!("not a workpiece element"),
116        }
117    }
118}