rs_flow/
connection.rs

1use std::collections::HashMap;
2
3use serde::{Serialize, Deserialize};
4
5use crate::component::Id;
6use crate::ports::PortId;
7use crate::error::{FlowError, Result};
8
9
10///
11/// A connection between two components, connecting this componets with a 
12/// [Output](crate::ports::Outputs) [Port](crate::ports::Port) of a [Component](crate::component::Component) 
13/// and a [Input](crate::ports::Inputs) [Port](crate::ports::Port) from the other [Component](crate::component::Component).
14/// 
15#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug)]
16pub struct Connection {
17    pub from: Id,
18    pub out_port: PortId,
19    pub to: Id,
20    pub in_port: PortId,
21}
22
23
24///
25/// This struct can represent a [Port](crate::ports::Port) of [`Input`](crate::ports::Inputs)/[`Output`](crate::ports::Outputs)  of a component.
26/// Two of this [Point] can represent a [Connection] that connect two components
27/// 
28/// ```
29/// use rs_flow::connection::{Point, Connection};
30/// 
31/// let from = Point::new(1, 0);
32/// let to = Point::new(2, 1);
33/// 
34/// let conn = Connection::by(from, to);
35/// 
36/// assert_eq!(conn.from(), from);
37/// assert_eq!(conn.to(), to);
38/// ```
39#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
40pub struct Point {
41    id: Id,
42    port: PortId,
43}
44impl Point {
45    /// Create a new Point
46    #[inline]
47    pub const fn new(id: Id, port: PortId) -> Self {
48        Self { id, port }
49    }
50
51    /// Id of component representation
52    #[inline]
53    pub fn id(&self) -> Id {
54        self.id
55    }
56
57    /// PortId of component representation port
58    #[inline]
59    pub fn port(&self) -> PortId {
60        self.port
61    }
62}
63
64
65impl From<(Id, PortId)> for Point {
66    #[inline]
67    fn from((id, port): (Id, PortId)) -> Self {
68        Point { id, port }
69    }
70}
71
72impl Connection {
73    /// Create a new connection
74    #[inline]
75    pub const fn new(from: Id, out_port: PortId, to: Id, in_port: PortId) -> Self {
76        Self {
77            from,
78            out_port,
79            to,
80            in_port,
81        }
82    }
83
84    /// Create a connection by two Points
85    #[inline]
86    pub const fn by(from: Point, to: Point) -> Self {
87        Self { 
88            from: from.id, 
89            out_port: from.port, 
90            to: to.id, 
91            in_port: to.port 
92        }
93    }
94
95    /// Return from Point of this connection 
96    #[inline]
97    pub fn from(&self) -> Point {
98        Point::new(self.from, self.out_port)
99    }
100
101    /// Return to Point of this connection 
102    #[inline]
103    pub fn to(&self) -> Point {
104        Point::new(self.to, self.in_port)
105    }
106}
107
108
109/// 
110/// Graph of Flow connections.
111///  
112/// This struct provide a rapid access to calculate ancestrals of a component
113/// that is usefull for know when components of [`Eager`](crate::component::Type#variant.Eager) type is ready to run.
114/// 
115/// That graph cannot create a Loop, end return a error if try
116/// add a connection that create a Loop.
117/// 
118#[derive(Debug, Clone)]
119pub(crate) struct Connections {
120    parents: HashMap<Id, Vec<Id>>,
121    connections: HashMap<Point, Vec<Point>>
122}
123
124
125/// Empty graph of Flow connections
126impl Default for Connections {
127    fn default() -> Connections {
128        Connections { 
129            parents: Default::default(),
130            connections: Default::default()
131        }
132    }
133}
134
135impl Connections {
136    /// Create a empty connections graph 
137    pub fn new() -> Self {
138        Self::default()
139    }
140
141    /// Insert a connection 
142    pub fn add(&mut self, connection: Connection) -> Result<()> {
143        if self.ancestral_of(connection.from, connection.to) {
144            return Err(FlowError::LoopCreated { connection }.into())
145        }
146
147        let entry = self.connections.entry(connection.from());
148        let to = connection.to();
149        let to_ports = entry.or_default();
150
151        if to_ports.contains(&to) {
152            return Err(FlowError::ConnectionAlreadyExist { connection }.into())
153        }
154        
155        to_ports.push(to);
156        
157        let parents = self.parents.entry(connection.to).or_default();
158        if !parents.contains(&connection.from) {
159            parents.push(connection.from);
160        }
161
162        Ok(())
163    }
164
165    
166    pub fn ancestral_of(&self, ancestral: Id, id: Id) -> bool {
167        if ancestral == id { // prevent component that connect to your self
168            return true;
169        }
170        if let Some(parents) = self.parents.get(&id) {
171            for parent in parents {
172                if *parent == ancestral || self.ancestral_of(ancestral, *parent) {
173                    return true;
174                }
175            }
176        }
177        
178        false
179    }
180
181    pub fn any_ancestral_of(&self, ancestrals: &[Id], id: Id) -> bool {
182        if ancestrals.contains(&id) { // prevent component that connect to your self
183            return true;
184        }
185
186        if let Some(parents) = self.parents.get(&id) {
187            for parent in parents {
188                if self.any_ancestral_of(ancestrals, *parent) {
189                    return true;
190                }
191            }
192        }
193
194        false
195    }
196
197    pub fn from(&self, from: Point) -> Option<&Vec<Point>> {
198        self.connections.get(&from)
199    }
200}