use alloc::{
borrow::ToOwned,
rc::Rc,
string::{String, ToString},
vec::Vec,
};
use crate::{
errors::NodeError,
shared::{StyleClass, StyleClassError, StyleProperty},
traits::{Node, NodeBuilder},
};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub(crate) struct GenericNode {
id: u64,
label: String,
classes: Vec<Rc<StyleClass>>,
style: Vec<StyleProperty>,
}
impl Node for GenericNode {
type Builder = GenericNodeBuilder;
fn id(&self) -> u64 {
self.id
}
fn label(&self) -> &str {
&self.label
}
fn classes(&self) -> impl Iterator<Item = &StyleClass> {
self.classes.iter().map(AsRef::as_ref)
}
fn styles(&self) -> impl Iterator<Item = &StyleProperty> {
self.style.iter()
}
fn is_compatible_arrow_shape(_shape: super::ArrowShape) -> bool {
true
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub(crate) struct GenericNodeBuilder {
id: Option<u64>,
label: Option<String>,
classes: Vec<Rc<StyleClass>>,
style: Vec<StyleProperty>,
}
impl TryFrom<GenericNodeBuilder> for GenericNode {
type Error = NodeError;
fn try_from(builder: GenericNodeBuilder) -> Result<Self, Self::Error> {
let id = builder.id.ok_or(NodeError::MissingId)?;
let label = builder.label.ok_or(NodeError::MissingLabel)?;
Ok(GenericNode { id, label, classes: builder.classes, style: builder.style })
}
}
impl NodeBuilder for GenericNodeBuilder {
type Node = GenericNode;
type Error = NodeError;
fn build(self) -> Result<Self::Node, Self::Error> {
self.try_into()
}
fn id(mut self, id: u64) -> Self {
self.id = Some(id);
self
}
fn get_id(&self) -> Option<u64> {
self.id
}
fn label<S: ToString>(mut self, label: S) -> Result<Self, Self::Error> {
let label = label.to_string();
if label.is_empty() {
return Err(crate::errors::NodeError::EmptyLabel);
}
self.label = Some(label);
Ok(self)
}
fn get_label(&self) -> Option<&String> {
self.label.as_ref()
}
fn style_class(mut self, style_class: Rc<StyleClass>) -> Result<Self, StyleClassError> {
if self.classes.iter().any(|c| c.name() == style_class.name()) {
return Err(StyleClassError::DuplicateClass(style_class.name().to_owned()));
}
self.classes.push(style_class);
Ok(self)
}
fn style_property(mut self, property: StyleProperty) -> Result<Self, StyleClassError> {
if self.style.iter().any(|p| p.is_same_type(property)) {
return Err(StyleClassError::DuplicateProperty(property));
}
self.style.push(property);
Ok(self)
}
fn style_properties(&self) -> impl Iterator<Item = &StyleProperty> {
self.style.iter()
}
}