use std::{cmp::Ordering, fmt::Display};
use serde::{Deserialize, Serialize};
use crate::{NodeStyle, TYPST_PREFIX};
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
pub enum NodeShape {
Circle,
#[default]
Rectangle,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Node {
label: String,
identifier: Option<String>,
shape: NodeShape,
object: Option<String>,
position: Option<(f32, f32)>,
style: Option<NodeStyle>,
}
impl Node {
pub fn new() -> Self {
Self::default()
}
pub fn from<L: Display>(label: L) -> Self {
Self {
label: label.to_string(),
..Default::default()
}
}
pub fn from_object<SVG: Display>(object: SVG) -> Self {
Self {
object: Some(object.to_string()),
..Default::default()
}
}
}
impl Node {
pub fn circle(mut self) -> Self {
self.shape = NodeShape::Circle;
self
}
pub fn identifier<S: Display>(mut self, identifier: S) -> Self {
self.identifier = Some(identifier.to_string());
self
}
pub fn label<L: Display>(mut self, label: L) -> Self {
self.label = label.to_string();
self
}
pub fn object<SVG: Display>(mut self, object: SVG) -> Self {
self.object = Some(object.to_string());
self
}
pub fn typst<T: Display>(mut self, typst: T) -> Self {
self.object = Some(format!("{TYPST_PREFIX}\n{typst}"));
self
}
pub fn position(mut self, x: f32, y: f32) -> Self {
self.position = Some((x, y));
self
}
pub fn style(mut self, nodestyle: NodeStyle) -> Self {
self.style = Some(nodestyle);
self
}
pub fn get_identifier(&self) -> Option<&str> {
self.identifier.as_deref()
}
pub fn get_label(&self) -> &str {
&self.label
}
pub fn get_shape(&self) -> &NodeShape {
&self.shape
}
pub fn get_object(&self) -> Option<&str> {
self.object.as_deref()
}
pub fn get_position(&self) -> Option<(f32, f32)> {
self.position
}
pub fn get_style(&self) -> Option<&NodeStyle> {
self.style.as_ref()
}
pub fn get_typst(&self) -> Option<String> {
if let Some(content) = &self.object {
if content.starts_with(TYPST_PREFIX) {
return Some(content.replace(TYPST_PREFIX, ""));
}
}
None
}
}
impl Eq for Node {}
impl PartialEq for Node {
fn eq(&self, other: &Self) -> bool {
self.label == other.label
&& self.identifier == other.identifier
&& self.shape == other.shape
&& self.object == other.object
&& self.position == other.position
}
}
impl Ord for Node {
fn cmp(&self, other: &Self) -> Ordering {
self.label
.cmp(&other.label)
.then_with(|| self.identifier.cmp(&other.identifier))
.then_with(|| self.shape.cmp(&other.shape))
.then_with(|| self.object.cmp(&other.object))
}
}
impl PartialOrd for Node {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}