use crate::node::NodeId;
use std::fmt;
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EdgeId(Arc<str>);
impl EdgeId {
#[must_use]
pub fn new() -> Self {
Self(nanoid::nanoid!(8).into())
}
#[must_use]
pub fn from_string(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl Default for EdgeId {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for EdgeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "edge_{}", self.0)
}
}
#[derive(Debug)]
pub enum Edge {
Sequential(SequentialEdge),
Conditional(ConditionalEdge),
Parallel(ParallelEdge),
LoopBack(LoopBackEdge),
Error(ErrorEdge),
Timeout(TimeoutEdge),
}
impl Edge {
#[must_use]
pub fn id(&self) -> EdgeId {
match self {
Edge::Sequential(edge) => edge.id.clone(),
Edge::Conditional(edge) => edge.id.clone(),
Edge::Parallel(edge) => edge.id.clone(),
Edge::LoopBack(edge) => edge.id.clone(),
Edge::Error(edge) => edge.id.clone(),
Edge::Timeout(edge) => edge.id.clone(),
}
}
#[must_use]
pub fn from(&self) -> NodeId {
match self {
Edge::Sequential(edge) => edge.from.clone(),
Edge::Conditional(edge) => edge.from.clone(),
Edge::Parallel(edge) => edge.from.clone(),
Edge::LoopBack(edge) => edge.from.clone(),
Edge::Error(edge) => edge.from.clone(),
Edge::Timeout(edge) => edge.from.clone(),
}
}
}
#[derive(Debug)]
pub struct SequentialEdge {
pub id: EdgeId,
pub from: NodeId,
pub to: NodeId,
}
impl SequentialEdge {
#[must_use]
pub fn new(from: NodeId, to: NodeId) -> Self {
Self {
id: EdgeId::new(),
from,
to,
}
}
}
#[derive(Debug)]
pub struct ConditionalEdge {
pub id: EdgeId,
pub from: NodeId,
pub true_target: NodeId,
pub false_target: NodeId,
}
impl ConditionalEdge {
#[must_use]
pub fn new(from: NodeId, true_target: NodeId, false_target: NodeId) -> Self {
Self {
id: EdgeId::new(),
from,
true_target,
false_target,
}
}
}
#[derive(Debug)]
pub struct ParallelEdge {
pub id: EdgeId,
pub from: NodeId,
pub targets: Vec<NodeId>,
}
impl ParallelEdge {
#[must_use]
pub fn new(from: NodeId, targets: Vec<NodeId>) -> Self {
Self {
id: EdgeId::new(),
from,
targets,
}
}
}
#[derive(Debug)]
pub struct LoopBackEdge {
pub id: EdgeId,
pub from: NodeId,
pub to: NodeId,
}
impl LoopBackEdge {
#[must_use]
pub fn new(from: NodeId, to: NodeId) -> Self {
Self {
id: EdgeId::new(),
from,
to,
}
}
}
#[derive(Debug)]
pub struct ErrorEdge {
pub id: EdgeId,
pub from: NodeId,
pub to: NodeId,
}
impl ErrorEdge {
#[must_use]
pub fn new(from: NodeId, to: NodeId) -> Self {
Self {
id: EdgeId::new(),
from,
to,
}
}
}
#[derive(Debug)]
pub struct TimeoutEdge {
pub id: EdgeId,
pub from: NodeId,
pub to: NodeId,
}
impl TimeoutEdge {
#[must_use]
pub fn new(from: NodeId, to: NodeId) -> Self {
Self {
id: EdgeId::new(),
from,
to,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn edge_id_uniqueness() {
let id1 = EdgeId::new();
let id2 = EdgeId::new();
assert_ne!(id1, id2);
}
#[test]
fn sequential_edge_creation() {
let from = NodeId::from_string("n1");
let to = NodeId::from_string("n2");
let edge = SequentialEdge::new(from.clone(), to.clone());
assert!(!edge.id.as_str().is_empty());
assert_eq!(edge.from.as_str(), "n1");
assert_eq!(edge.to.as_str(), "n2");
}
#[test]
fn edge_enum_accessors() {
let from = NodeId::from_string("n1");
let to = NodeId::from_string("n2");
let seq = Edge::Sequential(SequentialEdge::new(from, to));
assert!(!seq.id().as_str().is_empty());
assert_eq!(seq.from().as_str(), "n1");
}
}