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