use std::fmt::Debug;
use std::hash::Hash;
use derive_more::{From, Into};
use derive_where::derive_where;
use serde::{Deserialize, Serialize};
use crate::{port_diff::Owned, Graph};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum EdgeEnd {
Left,
Right,
}
impl EdgeEnd {
pub fn opposite(&self) -> Self {
match self {
Self::Left => Self::Right,
Self::Right => Self::Left,
}
}
}
#[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub struct Site<N, P> {
pub node: N,
pub port: P,
}
impl<N, P> Site<N, P> {
pub fn map_node(self, f: impl FnOnce(N) -> N) -> Site<N, P> {
Site {
node: f(self.node),
port: self.port,
}
}
pub fn filter_map_node(self, f: impl FnOnce(N) -> Option<N>) -> Option<Site<N, P>> {
Some(Site {
node: f(self.node)?,
port: self.port,
})
}
}
#[derive(
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, From, Into, Serialize, Deserialize,
)]
pub struct BoundaryIndex(usize);
#[derive(Debug, From, Serialize, Deserialize)]
#[serde(bound(
serialize = "G::Edge: Serialize",
deserialize = "G::Edge: Deserialize<'de>"
))]
#[derive_where(PartialEq; G: Graph)]
#[derive_where(Eq; G: Graph)]
#[derive_where(PartialOrd; G: Graph)]
#[derive_where(Ord; G: Graph)]
pub enum Port<G: Graph> {
Boundary(BoundaryIndex),
Bound(BoundPort<G::Edge>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct BoundPort<E> {
pub edge: E,
pub end: EdgeEnd,
}
impl<G: Graph> Clone for Port<G> {
fn clone(&self) -> Self {
match self {
Self::Boundary(i) => Self::Boundary(*i),
Self::Bound(port) => Self::Bound(port.clone()),
}
}
}
impl<G: Graph> Copy for Port<G> where G::Edge: Copy {}
impl<G: Graph> Owned<Port<G>, G> {
pub fn site(&self) -> Option<Site<G::Node, G::PortLabel>> {
match self.data {
Port::Boundary(boundary) => self.owner.boundary_site(boundary).clone().try_into().ok(),
Port::Bound(port) => Some(self.owner.graph().get_port_site(port)),
}
}
}
impl<E: Copy> BoundPort<E> {
pub fn opposite(&self) -> Self {
Self {
edge: self.edge,
end: self.end.opposite(),
}
}
}
impl<G: Graph> TryFrom<BoundarySite<G>> for Site<G::Node, G::PortLabel> {
type Error = BoundarySite<G>;
fn try_from(value: BoundarySite<G>) -> Result<Self, Self::Error> {
value.try_into_site()
}
}
#[derive(Serialize, Deserialize, From)]
#[derive_where(PartialEq, Eq, PartialOrd, Ord, Clone; G: Graph)]
#[derive_where(Debug; G: Graph, G::Node: Debug, G::PortLabel: Debug)]
#[derive_where(Hash; G: Graph, G::Node: Hash, G::PortLabel: Hash)]
#[serde(bound(
serialize = "G::Node: Serialize, G::PortLabel: Serialize",
deserialize = "G::Node: Deserialize<'de>, G::PortLabel: Deserialize<'de>"
))]
pub enum BoundarySite<G: Graph> {
Site(Site<G::Node, G::PortLabel>),
Wire { id: usize, end: EdgeEnd },
}
impl<G: Graph> BoundarySite<G> {
pub fn try_as_site_ref(&self) -> Option<&Site<G::Node, G::PortLabel>> {
match self {
Self::Site(site) => Some(site),
Self::Wire { .. } => None,
}
}
pub fn try_into_site(self) -> Result<Site<G::Node, G::PortLabel>, Self> {
match self {
Self::Site(site) => Ok(site),
Self::Wire { .. } => Err(self),
}
}
pub fn unwrap_site(self) -> Site<G::Node, G::PortLabel> {
self.try_into_site().ok().unwrap()
}
}