use compact_str::CompactString;
use crate::graph::GraphStorage;
use crate::value::TraverserValue;
pub struct TraverserPath<S: GraphStorage> {
pub(crate) steps: Vec<TraverserPathStep<S>>,
}
impl<S: GraphStorage> Default for TraverserPath<S> {
fn default() -> Self {
Self { steps: Vec::new() }
}
}
impl<S: GraphStorage> std::fmt::Debug for TraverserPath<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TraverserPath")
.field("steps", &self.steps)
.finish()
}
}
impl<S: GraphStorage> Clone for TraverserPath<S> {
fn clone(&self) -> Self {
Self {
steps: self.steps.clone(),
}
}
}
impl<S: GraphStorage> PartialEq for TraverserPath<S> {
fn eq(&self, other: &Self) -> bool {
self.steps == other.steps
}
}
impl<S: GraphStorage> Eq for TraverserPath<S> {}
impl<S: GraphStorage> core::hash::Hash for TraverserPath<S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.steps.hash(state);
}
}
pub(crate) struct TraverserPathStep<S: GraphStorage> {
pub(crate) value: TraverserValue<S>,
pub(crate) label: Option<Vec<CompactString>>,
}
impl<S: GraphStorage> std::fmt::Debug for TraverserPathStep<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TraverserPathStep")
.field("value", &self.value)
.field("label", &self.label)
.finish()
}
}
impl<S: GraphStorage> Clone for TraverserPathStep<S> {
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
label: self.label.clone(),
}
}
}
impl<S: GraphStorage> PartialEq for TraverserPathStep<S> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value && self.label == other.label
}
}
impl<S: GraphStorage> Eq for TraverserPathStep<S> {}
impl<S: GraphStorage> core::hash::Hash for TraverserPathStep<S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
self.label.hash(state);
}
}
impl<S: GraphStorage> TraverserPath<S> {
pub fn len(&self) -> usize {
self.steps.len()
}
pub fn is_empty(&self) -> bool {
self.steps.is_empty()
}
pub fn objects(&self) -> impl Iterator<Item = &TraverserValue<S>> {
self.steps.iter().map(|step| &step.value)
}
pub fn labels(&self, position: usize) -> Option<&[CompactString]> {
self.steps
.get(position)
.and_then(|step| step.label.as_deref())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::TraversalGraph;
use crate::value::ElementProperty;
use fnv::FnvHasher;
use std::hash::{Hash, Hasher};
fn calculate_hash<T: Hash>(t: &T) -> u64 {
let mut s = FnvHasher::default();
t.hash(&mut s);
s.finish()
}
#[test]
fn test_traverser_path_equality_and_hash() {
let val1: TraverserValue<TraversalGraph> =
TraverserValue::Computed(ElementProperty::String("a".into()), None);
let val2: TraverserValue<TraversalGraph> =
TraverserValue::Computed(ElementProperty::String("b".into()), None);
let path1 = TraverserPath {
steps: vec![TraverserPathStep {
value: val1.clone(),
label: Some(vec![CompactString::new("label1")]),
}],
};
let path1_clone = path1.clone();
let path2 = TraverserPath {
steps: vec![TraverserPathStep {
value: val2,
label: Some(vec![CompactString::new("label1")]),
}],
};
assert_eq!(path1, path1);
assert_eq!(path1, path1_clone);
assert_ne!(path1, path2);
assert_eq!(calculate_hash(&path1), calculate_hash(&path1_clone));
}
}