use super::{ConcurrentEdgeStore, GraphEdge};
use std::collections::{HashSet, VecDeque};
impl ConcurrentEdgeStore {
#[must_use]
pub fn get_outgoing(&self, node_id: u64) -> Vec<GraphEdge> {
let shard = &self.shards[self.shard_index(node_id)];
let guard = shard.read();
guard.get_outgoing(node_id).into_iter().cloned().collect()
}
#[must_use]
pub fn get_incoming(&self, node_id: u64) -> Vec<GraphEdge> {
let shard = &self.shards[self.shard_index(node_id)];
let guard = shard.read();
guard.get_incoming(node_id).into_iter().cloned().collect()
}
#[must_use]
pub fn get_neighbors(&self, node_id: u64) -> Vec<u64> {
self.get_outgoing(node_id)
.iter()
.map(GraphEdge::target)
.collect()
}
#[must_use]
pub fn get_outgoing_by_label(&self, node_id: u64, label: &str) -> Vec<GraphEdge> {
let shard_idx = self.shard_index(node_id);
let shard = self.shards[shard_idx].read();
shard
.get_outgoing_by_label(node_id, label)
.into_iter()
.cloned()
.collect()
}
#[must_use]
pub fn get_incoming_by_label(&self, node_id: u64, label: &str) -> Vec<GraphEdge> {
self.get_incoming(node_id)
.into_iter()
.filter(|e| e.label() == label)
.collect()
}
#[must_use]
pub fn get_edges_by_label(&self, label: &str) -> Vec<GraphEdge> {
self.shards
.iter()
.flat_map(|shard| {
shard
.read()
.get_edges_by_label(label)
.into_iter()
.cloned()
.collect::<Vec<_>>()
})
.collect()
}
#[must_use]
pub fn contains_edge(&self, edge_id: u64) -> bool {
self.edge_ids.read().contains_key(&edge_id)
}
#[must_use]
pub fn get_edge(&self, edge_id: u64) -> Option<GraphEdge> {
let source_id = *self.edge_ids.read().get(&edge_id)?;
let shard_idx = self.shard_index(source_id);
self.shards[shard_idx].read().get_edge(edge_id).cloned()
}
#[must_use]
pub fn traverse_bfs(&self, start: u64, max_depth: u32) -> Vec<u64> {
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
queue.push_back((start, 0u32));
while let Some((node, depth)) = queue.pop_front() {
if depth > max_depth || !visited.insert(node) {
continue;
}
let neighbors: Vec<u64> = {
let shard = &self.shards[self.shard_index(node)];
let guard = shard.read();
guard
.get_outgoing(node)
.iter()
.map(|e| e.target())
.collect()
};
for neighbor in neighbors {
if !visited.contains(&neighbor) {
queue.push_back((neighbor, depth + 1));
}
}
}
visited.into_iter().collect()
}
#[must_use]
pub fn edge_count(&self) -> usize {
self.shards
.iter()
.map(|s| s.read().outgoing_edge_count())
.sum()
}
}