use std::cmp;
use std::hash::Hash;
use std::ops::{Deref, DerefMut};
use super::hash::NodeHasher;
pub trait Node {
type NodeId: Hash + PartialEq + Ord;
type HashCode: Ord;
fn node_id(&self) -> &Self::NodeId;
fn hash_code<H, U: Hash>(&self, hasher: &H, item: &U) -> Self::HashCode
where
H: NodeHasher<Self::NodeId>;
}
impl<T: Node> Node for &T {
type NodeId = T::NodeId;
type HashCode = T::HashCode;
fn node_id(&self) -> &Self::NodeId {
(**self).node_id()
}
fn hash_code<H, U: Hash>(&self, hasher: &H, item: &U) -> Self::HashCode
where
H: NodeHasher<Self::NodeId>,
{
(**self).hash_code(hasher, item)
}
}
impl<'a> Node for &'a str {
type NodeId = Self;
type HashCode = u64;
fn node_id(&self) -> &Self::NodeId {
self
}
fn hash_code<H, U: Hash>(&self, hasher: &H, item: &U) -> Self::HashCode
where
H: NodeHasher<Self::NodeId>,
{
hasher.hash(self, item)
}
}
#[derive(Debug, Clone)]
pub struct IdNode<T>(T);
impl<T> IdNode<T> {
pub fn new(node: T) -> Self {
IdNode(node)
}
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> Deref for IdNode<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for IdNode<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> Node for IdNode<T>
where
T: Hash + PartialEq + Ord,
{
type NodeId = T;
type HashCode = u64;
fn node_id(&self) -> &Self::NodeId {
&self.0
}
fn hash_code<H, U: Hash>(&self, hasher: &H, item: &U) -> Self::HashCode
where
H: NodeHasher<Self::NodeId>,
{
hasher.hash(self.node_id(), item)
}
}
#[derive(Debug, Clone)]
pub struct KeyValueNode<K, V> {
pub key: K,
pub value: V,
}
impl<K, V> KeyValueNode<K, V> {
pub fn new(key: K, value: V) -> Self {
KeyValueNode { key, value }
}
}
impl<K, V> Node for KeyValueNode<K, V>
where
K: Hash + PartialEq + Ord,
{
type NodeId = K;
type HashCode = u64;
fn node_id(&self) -> &Self::NodeId {
&self.key
}
fn hash_code<H, U: Hash>(&self, hasher: &H, item: &U) -> Self::HashCode
where
H: NodeHasher<Self::NodeId>,
{
hasher.hash(self.node_id(), item)
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct SignPositiveF64(f64);
impl Eq for SignPositiveF64 {}
#[allow(clippy::derive_ord_xor_partial_ord)]
impl cmp::Ord for SignPositiveF64 {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.0.partial_cmp(&other.0).unwrap()
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Capacity(f64);
impl Capacity {
pub fn new(value: f64) -> Option<Self> {
if value.is_normal() && value.is_sign_positive() {
Some(Capacity(value))
} else {
None
}
}
pub fn value(self) -> f64 {
self.0
}
}
#[derive(Debug, Clone)]
pub struct WeightedNode<N> {
pub node: N,
pub capacity: Capacity,
}
impl<N: Node> WeightedNode<N> {
pub fn new(node: N, capacity: Capacity) -> Self {
WeightedNode { node, capacity }
}
}
impl<N: Node> Node for WeightedNode<N> {
type NodeId = N::NodeId;
type HashCode = SignPositiveF64;
fn node_id(&self) -> &Self::NodeId {
self.node.node_id()
}
fn hash_code<H, U: Hash>(&self, hasher: &H, item: &U) -> Self::HashCode
where
H: NodeHasher<Self::NodeId>,
{
use std::u64::MAX;
let hash = hasher.hash(self.node_id(), item) as f64;
let distance = (hash / MAX as f64).ln();
SignPositiveF64(distance / self.capacity.0)
}
}