use super::types::{CsrIndex, Direction};
impl CsrIndex {
pub fn neighbors_in_collection(
&self,
node: &str,
label_filter: Option<&str>,
direction: Direction,
collection: &str,
) -> Vec<(String, String)> {
let Some(&node_id) = self.node_to_id.get(node) else {
return Vec::new();
};
let Some(collection_id) = self.collection_id(collection) else {
return Vec::new();
};
self.record_access(node_id);
let label_id = label_filter.and_then(|l| self.label_to_id.get(l).copied());
let keep = |lid: u32| label_id.is_none_or(|f| f == lid);
let mut result = Vec::new();
if matches!(direction, Direction::Out | Direction::Both) {
for (lid, dst) in self.iter_out_edges_raw_in(node_id, collection_id) {
if keep(lid) {
result.push((
self.id_to_label[lid as usize].clone(),
self.id_to_node[dst as usize].clone(),
));
}
}
}
if matches!(direction, Direction::In | Direction::Both) {
for (lid, src) in self.iter_in_edges_raw_in(node_id, collection_id) {
if keep(lid) {
result.push((
self.id_to_label[lid as usize].clone(),
self.id_to_node[src as usize].clone(),
));
}
}
}
result
}
pub fn iter_out_edges_raw_in(
&self,
node: u32,
collection_id: u32,
) -> impl Iterator<Item = (u32, u32)> + '_ {
self.dense_scoped(node, collection_id, true).into_iter()
}
pub fn iter_in_edges_raw_in(
&self,
node: u32,
collection_id: u32,
) -> impl Iterator<Item = (u32, u32)> + '_ {
self.dense_scoped(node, collection_id, false).into_iter()
}
fn dense_scoped(&self, node: u32, collection_id: u32, outbound: bool) -> Vec<(u32, u32)> {
let idx = node as usize;
let (offsets, targets, labels, collections) = if outbound {
(
&self.out_offsets,
&self.out_targets,
&self.out_labels,
&self.out_collections,
)
} else {
(
&self.in_offsets,
&self.in_targets,
&self.in_labels,
&self.in_collections,
)
};
let mut result = Vec::new();
if idx + 1 < offsets.len() {
let start = offsets[idx] as usize;
let end = offsets[idx + 1] as usize;
for i in start..end {
if collections.get(i).copied().unwrap_or(0) != collection_id {
continue;
}
let lid = labels[i];
let other = targets[i];
let deleted = if outbound {
self.deleted_edges
.contains(&(node, lid, other, collection_id))
} else {
self.deleted_edges
.contains(&(other, lid, node, collection_id))
};
if !deleted {
result.push((lid, other));
}
}
}
let (buf, buf_coll) = if outbound {
(
self.buffer_out.get(idx),
self.buffer_out_collections.get(idx),
)
} else {
(self.buffer_in.get(idx), self.buffer_in_collections.get(idx))
};
if let (Some(buf), Some(buf_coll)) = (buf, buf_coll) {
for (k, &(lid, other)) in buf.iter().enumerate() {
if buf_coll.get(k).copied().unwrap_or(0) == collection_id {
result.push((lid, other));
}
}
}
result
}
}