microcad_lang/model/attribute/
mod.rs1mod attributes;
7mod export_command;
8mod layer;
9mod measure_command;
10mod resolution_attribute;
11
12pub use attributes::Attributes;
13pub use export_command::ExportCommand;
14pub use layer::Layer;
15pub use measure_command::MeasureCommand;
16pub use resolution_attribute::ResolutionAttribute;
17
18use crate::{syntax::*, value::*};
19
20use microcad_core::{Color, Size2};
21
22#[derive(Clone, Debug)]
24pub struct CustomCommand {
25 id: Identifier,
27 pub arguments: Box<Tuple>,
29}
30
31impl CustomCommand {
32 pub(crate) fn new(id: Identifier, arguments: Tuple) -> CustomCommand {
33 CustomCommand {
34 id,
35 arguments: arguments.into(),
36 }
37 }
38}
39
40impl Identifiable for CustomCommand {
41 fn id_ref(&self) -> &Identifier {
42 &self.id
43 }
44}
45
46impl std::fmt::Display for CustomCommand {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 write!(f, "{} = {}", self.id, self.arguments)
49 }
50}
51
52#[derive(Clone, Debug)]
54pub enum Attribute {
55 Color(Color),
57 Resolution(ResolutionAttribute),
59 Size(Size2),
61 Export(ExportCommand),
63 Measure(MeasureCommand),
65 Custom(CustomCommand),
67}
68
69impl Attribute {
70 fn id(&self) -> Identifier {
72 match &self {
73 Attribute::Color(_) => Identifier::no_ref("color"),
74 Attribute::Resolution(_) => Identifier::no_ref("resolution"),
75 Attribute::Size(_) => Identifier::no_ref("size"),
76 Attribute::Export(_) => Identifier::no_ref("export"),
77 Attribute::Measure(_) => Identifier::no_ref("measure"),
78 Attribute::Custom(attr) => attr.id(),
79 }
80 }
81
82 pub fn is_unique(&self) -> bool {
84 matches!(
85 self,
86 Attribute::Color(_) | Attribute::Resolution(_) | Attribute::Size(_)
87 )
88 }
89}
90
91impl std::fmt::Display for Attribute {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 write!(
94 f,
95 "#[{id} = {value}]",
96 id = self.id(),
97 value = match &self {
98 Attribute::Color(color) => format!("{color}"),
99 Attribute::Resolution(resolution) => format!("{resolution}"),
100 Attribute::Size(size) => format!("{size}"),
101 Attribute::Export(export) => format!("{export}"),
102 Attribute::Measure(measure) => format!("{measure}"),
103 Attribute::Custom(command) => format!("{command}"),
104 }
105 )
106 }
107}
108
109impl From<Attribute> for Value {
111 fn from(value: Attribute) -> Self {
112 match value {
113 Attribute::Color(color) => Value::Tuple(Box::new(color.into())),
114 Attribute::Resolution(resolution_attribute) => resolution_attribute.into(),
115 Attribute::Size(size) => size.into(),
116 Attribute::Export(e) => e.into(),
117 Attribute::Measure(m) => m.into(),
118 Attribute::Custom(attr) => Value::Tuple(attr.arguments.clone()),
119 }
120 }
121}
122
123impl PartialEq for Attribute {
124 fn eq(&self, other: &Self) -> bool {
125 self.id() == other.id()
126 }
127}
128
129pub trait AttributesAccess {
131 fn get_attributes_by_id(&self, id: &Identifier) -> Vec<Attribute>;
133
134 fn get_single_attribute(&self, id: &Identifier) -> Option<Attribute> {
136 let attributes = self.get_attributes_by_id(id);
137 match attributes.len() {
138 1 => attributes.first().cloned(),
139 _ => None,
140 }
141 }
142
143 fn get_attribute_value(&self, id: &Identifier) -> Value {
145 match self.get_single_attribute(id) {
146 Some(attribute) => attribute.into(),
147 None => Value::None,
148 }
149 }
150
151 fn get_resolution(&self) -> Option<ResolutionAttribute> {
153 match self.get_single_attribute(&Identifier::no_ref("resolution")) {
154 Some(value) => match value {
155 Attribute::Resolution(resolution) => Some(resolution),
156 _ => unreachable!(),
157 },
158 None => None,
159 }
160 }
161
162 fn get_color(&self) -> Option<Color> {
164 match self.get_single_attribute(&Identifier::no_ref("color")) {
165 Some(value) => match value {
166 Attribute::Color(color) => Some(color),
167 _ => unreachable!(),
168 },
169 None => None,
170 }
171 }
172
173 fn get_size(&self) -> Option<Size2> {
175 self.get_single_attribute(&Identifier::no_ref("size"))
176 .map(|attr| match attr {
177 Attribute::Size(size) => size,
178 _ => unreachable!(),
179 })
180 }
181
182 fn get_exports(&self) -> Vec<ExportCommand> {
184 self.get_attributes_by_id(&Identifier::no_ref("export"))
185 .into_iter()
186 .fold(Vec::new(), |mut exports, command| {
187 match command {
188 Attribute::Export(export_command) => exports.push(export_command.clone()),
189 _ => unreachable!(),
190 }
191 exports
192 })
193 }
194
195 fn get_measures(&self) -> Vec<MeasureCommand> {
197 self.get_attributes_by_id(&Identifier::no_ref("measure"))
198 .iter()
199 .fold(Vec::new(), |mut measures, attribute| {
200 match attribute {
201 Attribute::Measure(measure_command) => measures.push(measure_command.clone()),
202 _ => unreachable!(),
203 }
204 measures
205 })
206 }
207
208 fn get_custom_attributes(&self, id: &Identifier) -> Vec<Tuple> {
210 self.get_attributes_by_id(id)
211 .iter()
212 .fold(Vec::new(), |mut attributes, attribute| {
213 match attribute {
214 Attribute::Custom(attr) => attributes.push(attr.arguments.as_ref().clone()),
215 _ => unreachable!(),
216 }
217 attributes
218 })
219 }
220}