use petgraph::{
Direction,
data::DataMap,
visit::{
Data, GraphBase, GraphRef, IntoEdgeReferences, IntoEdges, IntoEdgesDirected, IntoNeighbors,
IntoNeighborsDirected,
},
};
use super::{BorrowDataCell, DataConflictErr, GraphElement, id_rwlock::IdLockReadGuard};
#[derive(Copy, Clone)]
pub struct LocalGraphView<G: GraphRef, C = NoConflictDetection> {
active_node: G::NodeId,
graph_ref: G,
_conflict_detection_type: std::marker::PhantomData<C>,
}
impl<G: GraphRef, C: ConflictDetectionType> LocalGraphView<G, C> {
pub(crate) fn new(graph_ref: G, active_node: G::NodeId) -> Self {
Self {
active_node,
graph_ref,
_conflict_detection_type: Default::default(),
}
}
}
impl<G: GraphRef, C> LocalGraphView<G, C> {
pub fn active_node(&self) -> G::NodeId {
self.active_node
}
pub fn base_graph(&self) -> G {
self.graph_ref
}
}
impl<G: GraphRef, C> GraphBase for LocalGraphView<G, C> {
type EdgeId = G::EdgeId;
type NodeId = G::NodeId;
}
impl<G: Data + GraphRef, C> Data for LocalGraphView<G, C> {
type NodeWeight = G::NodeWeight;
type EdgeWeight = G::EdgeWeight;
}
impl<G: IntoNeighbors, C> IntoNeighbors for &LocalGraphView<G, C> {
type Neighbors = G::Neighbors;
fn neighbors(self, a: Self::NodeId) -> Self::Neighbors {
self.graph_ref.neighbors(a)
}
}
impl<G: IntoNeighborsDirected, C> IntoNeighborsDirected for &LocalGraphView<G, C> {
type NeighborsDirected = G::NeighborsDirected;
fn neighbors_directed(self, a: Self::NodeId, d: Direction) -> Self::NeighborsDirected {
self.graph_ref.neighbors_directed(a, d)
}
}
impl<G: IntoEdgeReferences + IntoEdges, C> IntoEdgeReferences for &LocalGraphView<G, C> {
type EdgeRef = G::EdgeRef;
type EdgeReferences = G::Edges;
fn edge_references(self) -> Self::EdgeReferences {
self.graph_ref.edges(self.active_node)
}
}
impl<G: IntoEdges, C> IntoEdges for &LocalGraphView<G, C> {
type Edges = G::Edges;
fn edges(self, a: Self::NodeId) -> Self::Edges {
self.graph_ref.edges(a)
}
}
impl<G: IntoEdgesDirected, C> IntoEdgesDirected for &LocalGraphView<G, C> {
type EdgesDirected = G::EdgesDirected;
fn edges_directed(self, a: Self::NodeId, d: Direction) -> Self::EdgesDirected {
self.graph_ref.edges_directed(a, d)
}
}
impl<G: DataMap + GraphRef, C> DataMap for LocalGraphView<G, C> {
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
self.graph_ref.node_weight(id)
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.graph_ref.edge_weight(id)
}
}
impl<G> LocalGraphView<G, FullConflictDetection>
where
G: GraphRef + DataMap,
G::NodeWeight: BorrowDataCell,
{
pub fn try_node_weight(&self, id: G::NodeId) -> Option<SyncNodeReadResult<'_, G>> {
let w = self.graph_ref.node_weight(id);
w.map(|w| {
w.borrow_data_cell()
.try_read()
.map_err(|err| DataConflictErr {
_graph_element: GraphElement::NodeId(id),
err: err.into(),
})
})
}
}
pub type SyncReadGuard<'a, T> = IdLockReadGuard<'a, <T as BorrowDataCell>::UserData>;
pub type SyncEdgeReadResult<'a, G> = Result<
SyncReadGuard<'a, <G as Data>::EdgeWeight>,
DataConflictErr<<G as GraphBase>::NodeId, <G as GraphBase>::EdgeId>,
>;
pub type SyncNodeReadResult<'a, G> = Result<
SyncReadGuard<'a, <G as Data>::NodeWeight>,
DataConflictErr<<G as GraphBase>::NodeId, <G as GraphBase>::EdgeId>,
>;
impl<G> LocalGraphView<G, FullConflictDetection>
where
G: GraphRef + DataMap,
G::EdgeWeight: BorrowDataCell,
{
pub fn try_edge_weight(&self, id: G::EdgeId) -> Option<SyncEdgeReadResult<'_, G>> {
let w = self.graph_ref.edge_weight(id);
w.map(|w| {
w.borrow_data_cell()
.try_read()
.map_err(|err| DataConflictErr {
_graph_element: GraphElement::EdgeId(id),
err: err.into(),
})
})
}
}
pub trait ConflictDetectionType {}
pub struct FullConflictDetection;
impl ConflictDetectionType for FullConflictDetection {}
pub struct NoConflictDetection;
impl ConflictDetectionType for NoConflictDetection {}