portdiff/
port.rs

1//! Data types for ports
2
3use std::fmt::Debug;
4use std::hash::Hash;
5
6use derive_more::{From, Into};
7use derive_where::derive_where;
8use serde::{Deserialize, Serialize};
9
10use crate::{port_diff::Owned, Graph};
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
13pub enum EdgeEnd {
14    Left,
15    Right,
16}
17
18impl EdgeEnd {
19    pub fn opposite(&self) -> Self {
20        match self {
21            Self::Left => Self::Right,
22            Self::Right => Self::Left,
23        }
24    }
25}
26
27/// Site: where ports can be connected.
28///
29/// Uniquely given by a node and a port label. There may be 0, 1 or multiple
30/// ports at the same site.
31#[derive(
32    Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
33)]
34pub struct Site<N, P> {
35    /// The node
36    pub node: N,
37    /// The port label
38    pub port: P,
39}
40
41impl<N, P> Site<N, P> {
42    pub fn map_node(self, f: impl FnOnce(N) -> N) -> Site<N, P> {
43        Site {
44            node: f(self.node),
45            port: self.port,
46        }
47    }
48
49    pub fn filter_map_node(self, f: impl FnOnce(N) -> Option<N>) -> Option<Site<N, P>> {
50        Some(Site {
51            node: f(self.node)?,
52            port: self.port,
53        })
54    }
55}
56
57/// A boundary port, given by the index of the port in the boundary.
58#[derive(
59    Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, From, Into, Serialize, Deserialize,
60)]
61pub struct BoundaryIndex(usize);
62
63/// A port in the graph, either connected to an edge or marking a subgraph boundary.
64///
65/// The port belongs to a site. There may be 0 or 1 edge connected to a port.
66#[derive(Debug, From, Serialize, Deserialize)]
67#[serde(bound(
68    serialize = "G::Edge: Serialize",
69    deserialize = "G::Edge: Deserialize<'de>"
70))]
71#[derive_where(PartialEq; G: Graph)]
72#[derive_where(Eq; G: Graph)]
73#[derive_where(PartialOrd; G: Graph)]
74#[derive_where(Ord; G: Graph)]
75pub enum Port<G: Graph> {
76    /// The i-th boundary port of the graph.
77    Boundary(BoundaryIndex),
78    /// A port connected to an edge.
79    Bound(BoundPort<G::Edge>),
80}
81
82/// A port that is connected to an edge.
83///
84/// This is given by a an edge and an edge end. This always determines the
85/// port uniquely.
86#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
87pub struct BoundPort<E> {
88    /// The edge
89    pub edge: E,
90    /// Whether it is the left or right end of the edge.
91    pub end: EdgeEnd,
92}
93
94impl<G: Graph> Clone for Port<G> {
95    fn clone(&self) -> Self {
96        match self {
97            Self::Boundary(i) => Self::Boundary(*i),
98            Self::Bound(port) => Self::Bound(port.clone()),
99        }
100    }
101}
102
103impl<G: Graph> Copy for Port<G> where G::Edge: Copy {}
104
105impl<G: Graph> Owned<Port<G>, G> {
106    pub fn site(&self) -> Option<Site<G::Node, G::PortLabel>> {
107        match self.data {
108            Port::Boundary(boundary) => self.owner.boundary_site(boundary).clone().try_into().ok(),
109            Port::Bound(port) => Some(self.owner.graph().get_port_site(port)),
110        }
111    }
112}
113
114// #[derive(Debug, PartialEq, Eq)]
115// pub(crate) struct ParentPort<G: Graph> {
116//     pub(crate) parent: PortDiff<G>,
117//     pub(crate) port: BoundPort<G::Edge>,
118// }
119
120// #[derive(Clone, Debug, PartialEq, Eq)]
121// pub(crate) struct ChildPort<G: Graph> {
122//     pub(crate) child: WeakPortDiff<G>,
123//     pub(crate) port: UnboundPort<G::Node, G::PortLabel>,
124// }
125
126impl<E: Copy> BoundPort<E> {
127    pub fn opposite(&self) -> Self {
128        Self {
129            edge: self.edge,
130            end: self.end.opposite(),
131        }
132    }
133}
134
135// impl<G: Graph> From<Site<G::Node, G::PortLabel>> for BoundarySite<G> {
136//     fn from(value: Site<G::Node, G::PortLabel>) -> Self {
137//         let site = Site {
138//             node: value.node,
139//             port: value.port,
140//         };
141//         Self(site)
142//     }
143// }
144
145impl<G: Graph> TryFrom<BoundarySite<G>> for Site<G::Node, G::PortLabel> {
146    type Error = BoundarySite<G>;
147
148    fn try_from(value: BoundarySite<G>) -> Result<Self, Self::Error> {
149        value.try_into_site()
150    }
151}
152
153/// A site of a boundary port.
154///
155/// Either a site of the graph or a site on an "imaginary" wire. As many
156/// such wires can be created as needed. For any wire ID, there may be at
157/// most one site for each end. Wires should be assigned increasing indices
158/// starting from 0.
159#[derive(Serialize, Deserialize, From)]
160#[derive_where(PartialEq, Eq, PartialOrd, Ord, Clone; G: Graph)]
161#[derive_where(Debug; G: Graph, G::Node: Debug, G::PortLabel: Debug)]
162#[derive_where(Hash; G: Graph, G::Node: Hash, G::PortLabel: Hash)]
163#[serde(bound(
164    serialize = "G::Node: Serialize, G::PortLabel: Serialize",
165    deserialize = "G::Node: Deserialize<'de>, G::PortLabel: Deserialize<'de>"
166))]
167pub enum BoundarySite<G: Graph> {
168    Site(Site<G::Node, G::PortLabel>),
169    Wire { id: usize, end: EdgeEnd },
170}
171
172impl<G: Graph> BoundarySite<G> {
173    pub fn try_as_site_ref(&self) -> Option<&Site<G::Node, G::PortLabel>> {
174        match self {
175            Self::Site(site) => Some(site),
176            Self::Wire { .. } => None,
177        }
178    }
179
180    pub fn try_into_site(self) -> Result<Site<G::Node, G::PortLabel>, Self> {
181        match self {
182            Self::Site(site) => Ok(site),
183            Self::Wire { .. } => Err(self),
184        }
185    }
186
187    pub fn unwrap_site(self) -> Site<G::Node, G::PortLabel> {
188        self.try_into_site().ok().unwrap()
189    }
190}