use std::collections::HashMap;
use serde::{Serialize, Deserialize};
use crate::component::Id;
use crate::ports::PortId;
use crate::error::{FlowError, Result};
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug)]
pub struct Connection {
pub from: Id,
pub out_port: PortId,
pub to: Id,
pub in_port: PortId,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct Point {
id: Id,
port: PortId,
}
impl Point {
#[inline]
pub const fn new(id: Id, port: PortId) -> Self {
Self { id, port }
}
#[inline]
pub fn id(&self) -> Id {
self.id
}
#[inline]
pub fn port(&self) -> PortId {
self.port
}
}
impl From<(Id, PortId)> for Point {
#[inline]
fn from((id, port): (Id, PortId)) -> Self {
Point { id, port }
}
}
impl Connection {
#[inline]
pub const fn new(from: Id, out_port: PortId, to: Id, in_port: PortId) -> Self {
Self {
from,
out_port,
to,
in_port,
}
}
#[inline]
pub const fn by(from: Point, to: Point) -> Self {
Self {
from: from.id,
out_port: from.port,
to: to.id,
in_port: to.port
}
}
#[inline]
pub fn from(&self) -> Point {
Point::new(self.from, self.out_port)
}
#[inline]
pub fn to(&self) -> Point {
Point::new(self.to, self.in_port)
}
}
#[derive(Debug, Clone)]
pub(crate) struct Connections {
parents: HashMap<Id, Vec<Id>>,
connections: HashMap<Point, Vec<Point>>
}
impl Default for Connections {
fn default() -> Connections {
Connections {
parents: Default::default(),
connections: Default::default()
}
}
}
impl Connections {
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, connection: Connection) -> Result<()> {
if self.ancestral_of(connection.from, connection.to) {
return Err(FlowError::LoopCreated { connection }.into())
}
let entry = self.connections.entry(connection.from());
let to = connection.to();
let to_ports = entry.or_default();
if to_ports.contains(&to) {
return Err(FlowError::ConnectionAlreadyExist { connection }.into())
}
to_ports.push(to);
let parents = self.parents.entry(connection.to).or_default();
if !parents.contains(&connection.from) {
parents.push(connection.from);
}
Ok(())
}
pub fn ancestral_of(&self, ancestral: Id, id: Id) -> bool {
if ancestral == id { return true;
}
if let Some(parents) = self.parents.get(&id) {
for parent in parents {
if *parent == ancestral || self.ancestral_of(ancestral, *parent) {
return true;
}
}
}
false
}
pub fn any_ancestral_of(&self, ancestrals: &[Id], id: Id) -> bool {
if ancestrals.contains(&id) { return true;
}
if let Some(parents) = self.parents.get(&id) {
for parent in parents {
if self.any_ancestral_of(ancestrals, *parent) {
return true;
}
}
}
false
}
pub fn from(&self, from: Point) -> Option<&Vec<Point>> {
self.connections.get(&from)
}
}