use alloc::vec::Vec;
use core::fmt::Display;
pub mod attribute;
mod builder;
use attribute::EntityRelationshipAttribute;
pub use builder::ERNodeBuilder;
use crate::{
shared::{GenericNode, NODE_LETTER, StyleClass, StyleProperty},
traits::Node,
};
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ERNode {
node: GenericNode,
attributes: Vec<EntityRelationshipAttribute>,
}
impl Node for ERNode {
type Builder = ERNodeBuilder;
fn label(&self) -> &str {
self.node.label()
}
fn id(&self) -> u64 {
self.node.id()
}
fn styles(&self) -> impl Iterator<Item = &StyleProperty> {
self.node.styles()
}
fn classes(&self) -> impl Iterator<Item = &StyleClass> {
self.node.classes()
}
fn is_compatible_arrow_shape(shape: crate::shared::ArrowShape) -> bool {
matches!(
shape,
crate::shared::ArrowShape::OneOrMore
| crate::shared::ArrowShape::ExactlyOne
| crate::shared::ArrowShape::ZeroOrOne
| crate::shared::ArrowShape::ZeroOrMore
)
}
}
impl Display for ERNode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use crate::traits::TabbedDisplay;
self.fmt_tabbed(f, 0)
}
}
impl crate::traits::TabbedDisplay for ERNode {
fn fmt_tabbed(&self, f: &mut core::fmt::Formatter<'_>, tab_count: usize) -> core::fmt::Result {
let indent = " ".repeat(tab_count * 2);
write!(f, "{indent}{NODE_LETTER}{}[\"{}\"]", self.id(), self.label())?;
if self.attributes.is_empty() {
writeln!(f)?;
} else {
writeln!(f, " {{")?;
for attr in &self.attributes {
writeln!(f, "{indent} {attr}")?;
}
writeln!(f, "{indent}}}")?;
}
for class in self.classes() {
writeln!(f, "{indent}class {NODE_LETTER}{} {}", self.id(), class.name())?;
}
Ok(())
}
}