use crate::digest::ValueDigest;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProximityNode<const N: usize> {
pub level: u8,
pub ids: Vec<Vec<u8>>,
pub vectors: Vec<Vec<f32>>,
pub child_hashes: Vec<ValueDigest<N>>,
pub dim: u16,
pub metric_tag: u8,
}
impl<const N: usize> ProximityNode<N> {
pub fn new(
level: u8,
ids: Vec<Vec<u8>>,
vectors: Vec<Vec<f32>>,
child_hashes: Vec<ValueDigest<N>>,
dim: u16,
metric_tag: u8,
) -> Self {
Self {
level,
ids,
vectors,
child_hashes,
dim,
metric_tag,
}
}
pub fn is_leaf(&self) -> bool {
self.level == 0
}
pub fn len(&self) -> usize {
self.ids.len()
}
pub fn is_empty(&self) -> bool {
self.ids.is_empty()
}
pub fn get_hash(&self) -> ValueDigest<N> {
let bytes = bincode::serialize(self).expect("ProximityNode bincode serialize");
ValueDigest::new(&bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn leaf_predicate() {
let n = ProximityNode::<32>::new(0, vec![b"a".to_vec()], vec![vec![1.0]], vec![], 1, 0);
assert!(n.is_leaf());
let n = ProximityNode::<32>::new(
1,
vec![b"a".to_vec()],
vec![vec![1.0]],
vec![ValueDigest::<32>::new(b"x")],
1,
0,
);
assert!(!n.is_leaf());
}
#[test]
fn deterministic_hash_independent_of_clone() {
let a = ProximityNode::<32>::new(
0,
vec![b"a".to_vec(), b"b".to_vec()],
vec![vec![1.0, 2.0], vec![3.0, 4.0]],
vec![],
2,
1,
);
let b = a.clone();
assert_eq!(a.get_hash(), b.get_hash());
}
#[test]
fn different_content_different_hash() {
let a = ProximityNode::<32>::new(0, vec![b"a".to_vec()], vec![vec![1.0]], vec![], 1, 0);
let b = ProximityNode::<32>::new(0, vec![b"a".to_vec()], vec![vec![2.0]], vec![], 1, 0);
assert_ne!(a.get_hash(), b.get_hash());
}
#[test]
fn bincode_roundtrip() {
let original = ProximityNode::<32>::new(
2,
vec![b"x".to_vec(), b"y".to_vec()],
vec![vec![0.1, 0.2], vec![0.3, 0.4]],
vec![ValueDigest::<32>::new(b"c0"), ValueDigest::<32>::new(b"c1")],
2,
1,
);
let bytes = bincode::serialize(&original).unwrap();
let restored: ProximityNode<32> = bincode::deserialize(&bytes).unwrap();
assert_eq!(original.level, restored.level);
assert_eq!(original.ids, restored.ids);
assert_eq!(original.vectors, restored.vectors);
assert_eq!(original.child_hashes, restored.child_hashes);
assert_eq!(original.dim, restored.dim);
assert_eq!(original.metric_tag, restored.metric_tag);
assert_eq!(original.get_hash(), restored.get_hash());
}
}