mod attributes;
mod export_command;
mod layer;
mod measure_command;
mod resolution_attribute;
pub use attributes::Attributes;
pub use export_command::ExportCommand;
pub use layer::Layer;
pub use measure_command::MeasureCommand;
pub use resolution_attribute::ResolutionAttribute;
use crate::value::*;
use microcad_core::{Color, Size2};
use microcad_lang_base::Identifier;
use microcad_lang_proc_macros::Identifiable;
#[derive(Clone, Debug, Identifiable)]
pub struct CustomCommand {
id: Identifier,
pub arguments: Box<Tuple>,
}
impl CustomCommand {
pub(crate) fn new(id: Identifier, arguments: Tuple) -> CustomCommand {
CustomCommand {
id,
arguments: arguments.into(),
}
}
}
impl std::fmt::Display for CustomCommand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} = {}", self.id, self.arguments)
}
}
#[derive(Clone, Debug)]
pub enum Attribute {
Color(Color),
Resolution(ResolutionAttribute),
Size(Size2),
Export(ExportCommand),
Measure(MeasureCommand),
Custom(CustomCommand),
}
impl Attribute {
fn id(&self) -> Identifier {
match &self {
Attribute::Color(_) => Identifier::no_ref("color"),
Attribute::Resolution(_) => Identifier::no_ref("resolution"),
Attribute::Size(_) => Identifier::no_ref("size"),
Attribute::Export(_) => Identifier::no_ref("export"),
Attribute::Measure(_) => Identifier::no_ref("measure"),
Attribute::Custom(attr) => attr.id.clone(),
}
}
pub fn is_unique(&self) -> bool {
matches!(
self,
Attribute::Color(_) | Attribute::Resolution(_) | Attribute::Size(_)
)
}
}
impl std::fmt::Display for Attribute {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"#[{id} = {value}]",
id = self.id(),
value = match &self {
Attribute::Color(color) => format!("{color}"),
Attribute::Resolution(resolution) => format!("{resolution}"),
Attribute::Size(size) => format!("{size}"),
Attribute::Export(export) => format!("{export}"),
Attribute::Measure(measure) => format!("{measure}"),
Attribute::Custom(command) => format!("{command}"),
}
)
}
}
impl From<Attribute> for Value {
fn from(value: Attribute) -> Self {
match value {
Attribute::Color(color) => Value::Tuple(Box::new(color.into())),
Attribute::Resolution(resolution_attribute) => resolution_attribute.into(),
Attribute::Size(size) => size.into(),
Attribute::Export(e) => e.into(),
Attribute::Measure(m) => m.into(),
Attribute::Custom(attr) => Value::Tuple(attr.arguments.clone()),
}
}
}
impl PartialEq for Attribute {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
pub trait AttributesAccess {
fn get_attributes_by_id(&self, id: &Identifier) -> Vec<Attribute>;
fn get_single_attribute(&self, id: &Identifier) -> Option<Attribute> {
let attributes = self.get_attributes_by_id(id);
match attributes.len() {
1 => attributes.first().cloned(),
_ => None,
}
}
fn get_attribute_value(&self, id: &Identifier) -> Value {
match self.get_single_attribute(id) {
Some(attribute) => attribute.into(),
None => Value::None,
}
}
fn get_resolution(&self) -> Option<ResolutionAttribute> {
match self.get_single_attribute(&Identifier::no_ref("resolution")) {
Some(value) => match value {
Attribute::Resolution(resolution) => Some(resolution),
_ => unreachable!(),
},
None => None,
}
}
fn get_color(&self) -> Option<Color> {
match self.get_single_attribute(&Identifier::no_ref("color")) {
Some(value) => match value {
Attribute::Color(color) => Some(color),
_ => unreachable!(),
},
None => None,
}
}
fn get_size(&self) -> Option<Size2> {
self.get_single_attribute(&Identifier::no_ref("size"))
.map(|attr| match attr {
Attribute::Size(size) => size,
_ => unreachable!(),
})
}
fn get_exports(&self) -> Vec<ExportCommand> {
self.get_attributes_by_id(&Identifier::no_ref("export"))
.into_iter()
.fold(Vec::new(), |mut exports, command| {
match command {
Attribute::Export(export_command) => exports.push(export_command.clone()),
_ => unreachable!(),
}
exports
})
}
fn get_measures(&self) -> Vec<MeasureCommand> {
self.get_attributes_by_id(&Identifier::no_ref("measure"))
.iter()
.fold(Vec::new(), |mut measures, attribute| {
match attribute {
Attribute::Measure(measure_command) => measures.push(measure_command.clone()),
_ => unreachable!(),
}
measures
})
}
fn get_custom_attributes(&self, id: &Identifier) -> Vec<Tuple> {
self.get_attributes_by_id(id)
.iter()
.fold(Vec::new(), |mut attributes, attribute| {
match attribute {
Attribute::Custom(attr) => attributes.push(attr.arguments.as_ref().clone()),
_ => unreachable!(),
}
attributes
})
}
}