microcad_lang/model/
element.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Element of a [`Model`].
5
6use crate::{builtin::*, model::*, syntax::*, 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    /// Children marker.
30    InputPlaceholder,
31}
32
33impl Element {
34    /// Get output type of element.
35    pub fn output_type(&self) -> OutputType {
36        match self {
37            Element::Workpiece(workpiece) => match workpiece.kind {
38                WorkbenchKind::Sketch => OutputType::Geometry2D,
39                WorkbenchKind::Part => OutputType::Geometry3D,
40                WorkbenchKind::Operation => OutputType::NotDetermined,
41            },
42            Element::BuiltinWorkpiece(builtin_workpiece) => match builtin_workpiece.kind {
43                BuiltinWorkbenchKind::Primitive2D => OutputType::Geometry2D,
44                BuiltinWorkbenchKind::Primitive3D => OutputType::Geometry3D,
45                BuiltinWorkbenchKind::Transform | BuiltinWorkbenchKind::Operation => {
46                    builtin_workpiece.output_type
47                }
48            },
49            Element::Group | Element::Multiplicity | Element::InputPlaceholder => {
50                OutputType::NotDetermined
51            }
52        }
53    }
54
55    /// Check if an element is an operation.
56    pub fn is_operation(&self) -> bool {
57        match self {
58            Element::BuiltinWorkpiece(builtin_workpiece) => match builtin_workpiece.kind {
59                BuiltinWorkbenchKind::Primitive2D | BuiltinWorkbenchKind::Primitive3D => false,
60                BuiltinWorkbenchKind::Operation | BuiltinWorkbenchKind::Transform => true,
61            },
62            Element::Multiplicity | Element::Group | Element::InputPlaceholder => false,
63            Element::Workpiece(workpiece) => match workpiece.kind {
64                WorkbenchKind::Part | WorkbenchKind::Sketch => false,
65                WorkbenchKind::Operation => true,
66            },
67        }
68    }
69}
70
71impl std::fmt::Display for Element {
72    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
73        let name: &'static str = self.into();
74        match &self {
75            Element::Workpiece(workpiece) => write!(f, "{workpiece}"),
76            Element::BuiltinWorkpiece(builtin_workpiece) => write!(f, "{builtin_workpiece}"),
77            _ => write!(f, "{name}"),
78        }
79    }
80}
81
82impl PropertiesAccess for Element {
83    fn get_property(&self, id: &Identifier) -> Option<&Value> {
84        match self {
85            Self::Workpiece(workpiece) => workpiece.get_property(id),
86            _ => unreachable!("not a workpiece element"),
87        }
88    }
89
90    fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
91        match self {
92            Self::Workpiece(workpiece) => workpiece.set_property(id, value),
93            _ => unreachable!("not a workpiece element"),
94        }
95    }
96
97    fn get_properties(&self) -> Option<&Properties> {
98        match self {
99            Self::Workpiece(workpiece) => workpiece.get_properties(),
100            _ => None,
101        }
102    }
103
104    fn add_properties(&mut self, props: Properties) {
105        match self {
106            Self::Workpiece(workpiece) => {
107                workpiece.add_properties(props);
108            }
109            _ => unreachable!("not a workpiece element"),
110        }
111    }
112}