pub mod attribute;
pub mod builder;
pub mod creator;
pub mod element;
mod inner;
pub mod iter;
pub mod models;
pub mod operation;
pub mod output_type;
pub mod properties;
pub mod workpiece;
pub use attribute::*;
pub use builder::*;
pub use creator::*;
pub use element::*;
pub use inner::*;
pub use iter::*;
pub use models::*;
pub use operation::*;
pub use output_type::*;
pub use properties::*;
pub use workpiece::*;
use derive_more::{Deref, DerefMut};
use microcad_core::{
BooleanOp, Integer,
hash::{ComputedHash, HashId},
};
use microcad_lang_base::{
Identifier, RcMut, SrcRef, SrcReferrer, TreeDisplay, TreeState, WriteToFile,
};
use crate::{lower::ir::WorkbenchKind, value::Value};
#[derive(Clone, Deref, DerefMut)]
pub struct Model(RcMut<ModelInner>);
impl Model {
pub fn new(inner: RcMut<ModelInner>) -> Self {
Self(inner)
}
pub fn is_empty(&self) -> bool {
self.borrow().is_empty()
}
pub fn has_no_output(&self) -> bool {
let self_ = self.borrow();
match self_.element.value {
Element::BuiltinWorkpiece(_) | Element::InputPlaceholder => false,
_ => self_.is_empty(),
}
}
pub fn make_deep_copy(&self) -> Self {
let copy = Self(RcMut::new(self.0.borrow().clone_content()));
for child in self.borrow().children.iter() {
copy.append(child.make_deep_copy());
}
copy
}
pub fn addr(&self) -> usize {
self.0.as_ptr().addr()
}
pub fn append(&self, model: Model) -> Model {
model.borrow_mut().parent = Some(self.clone());
let mut self_ = self.0.borrow_mut();
self_.children.push(model.clone());
model
}
pub fn append_children(&self, models: Models) -> Self {
for model in models.iter() {
self.append(model.clone());
}
self.clone()
}
pub fn boolean_op(self, op: BooleanOp, other: Model) -> Model {
assert!(self != other, "lhs and rhs must be distinct.");
Models::from(vec![self.clone(), other]).boolean_op(op)
}
pub fn multiply(&self, n: Integer) -> Vec<Model> {
(0..n).map(|_| self.make_deep_copy()).collect()
}
pub fn replace_input_placeholders(&self, input_model: &Model) -> Self {
self.descendants().for_each(|model| {
let mut model_ = model.borrow_mut();
if model_.id.is_none() && matches!(model_.element.value, Element::InputPlaceholder) {
let input_model_ = input_model.borrow_mut();
*model_ = input_model_.clone_content();
model_.parent = Some(self.clone());
model_.children = input_model_.children.clone();
}
});
self.clone()
}
pub fn deduce_output_type(&self) -> OutputType {
let self_ = self.borrow();
let mut output_type = self_.element.output_type();
if output_type == OutputType::NotDetermined {
let children = &self_.children;
output_type = children.deduce_output_type();
}
output_type
}
pub fn render_output_type(&self) -> OutputType {
let self_ = self.borrow();
self_
.output
.as_ref()
.map(|output| output.output_type)
.unwrap_or(OutputType::InvalidMixed)
}
pub fn into_group(&self) -> Option<Model> {
self.borrow()
.children
.single_model()
.filter(|model| matches!(model.borrow().element.value, Element::Group))
}
pub fn set_id(&self, id: Identifier) {
self.borrow_mut().id = Some(id);
}
}
impl Model {
pub fn descendants(&self) -> Descendants {
Descendants::new(self.clone())
}
pub fn multiplicity_descendants(&self) -> MultiplicityDescendants {
MultiplicityDescendants::new(self.clone())
}
pub fn source_file_descendants(&self) -> SourceFileDescendants {
SourceFileDescendants::new(self.clone())
}
pub fn parents(&self) -> Parents {
Parents::new(self.clone())
}
pub fn ancestors(&self) -> Ancestors {
Ancestors::new(self.clone())
}
pub fn get_property(&self, id: &Identifier) -> Option<Value> {
self.borrow().element.get_property(id).cloned()
}
pub fn set_property(&mut self, id: Identifier, value: Value) -> Option<Value> {
self.borrow_mut().element.set_property(id, value)
}
pub fn add_property(&self, id: Identifier, value: Value) {
self.borrow_mut()
.element
.add_properties([(id, value)].into_iter().collect())
}
}
impl AttributesAccess for Model {
fn get_attributes_by_id(&self, id: &Identifier) -> Vec<Attribute> {
self.borrow().attributes.get_attributes_by_id(id)
}
}
impl PartialEq for Model {
fn eq(&self, other: &Self) -> bool {
self.addr() == other.addr()
}
}
impl SrcReferrer for Model {
fn src_ref(&self) -> SrcRef {
self.borrow().src_ref()
}
}
impl std::fmt::Display for Model {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{id}{element}{is_root} ->",
id = match &self.borrow().id {
Some(id) => format!("{id}: "),
None => String::new(),
},
element = *self.borrow().element,
is_root = if self.parents().next().is_some() {
""
} else {
" (root)"
}
)
}
}
impl std::fmt::Debug for Model {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
microcad_lang_base::shorten(
&format!(
"{id}{element}{is_root} ->",
id = match &self.borrow().id {
Some(id) => format!("{id:?}: "),
None => String::new(),
},
element = *self.borrow().element,
is_root = if self.parents().next().is_some() {
""
} else {
" (root)"
}
),
140
)
)
}
}
impl TreeDisplay for Model {
fn tree_print(
&self,
f: &mut std::fmt::Formatter,
mut tree_state: TreeState,
) -> std::fmt::Result {
let signature = if tree_state.debug {
format!("{self:?}")
} else {
self.to_string()
};
let self_ = self.borrow();
if let Some(output) = &self_.output {
writeln!(f, "{:tree_state$}{signature} {output}", "",)?;
} else {
writeln!(f, "{:tree_state$}{signature}", "",)?;
}
tree_state.indent();
if let Some(props) = self_.get_properties() {
props.tree_print(f, tree_state)?;
}
self_.attributes.tree_print(f, tree_state)?;
self_.children.tree_print(f, tree_state)
}
}
impl WriteToFile for Model {}
impl std::hash::Hash for Model {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let self_ = self.borrow();
self_.element().hash(state);
self_.children().for_each(|child| child.hash(state));
}
}
impl ComputedHash for Model {
fn computed_hash(&self) -> HashId {
let self_ = self.borrow();
self_.output().computed_hash()
}
}