crayon 0.7.1

A small, portable and extensible game framework.
Documentation
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::path::Path;

use super::hash;

#[derive(Serialize, Deserialize, Debug, Eq)]
pub struct HashValue<T>(u64, PhantomData<T>)
where
    T: Hash + ?Sized;

impl<T> HashValue<T>
where
    T: Hash + ?Sized,
{
    pub fn zero() -> Self {
        HashValue(0, PhantomData)
    }
}

impl<T> Clone for HashValue<T>
where
    T: Hash + ?Sized,
{
    fn clone(&self) -> Self {
        HashValue(self.0, self.1)
    }
}

impl<T> Copy for HashValue<T> where T: Hash + ?Sized {}

impl<T> PartialEq for HashValue<T>
where
    T: Hash + ?Sized,
{
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }
}

impl<T> Hash for HashValue<T>
where
    T: Hash + ?Sized,
{
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        self.0.hash(state);
    }
}

impl<F> From<F> for HashValue<str>
where
    F: AsRef<str>,
{
    fn from(v: F) -> Self {
        HashValue(hash::hash64(v.as_ref()), PhantomData)
    }
}

impl<T> From<T> for HashValue<Path>
where
    T: AsRef<Path>,
{
    fn from(v: T) -> Self {
        HashValue(hash::hash64(v.as_ref()), PhantomData)
    }
}

impl<T> PartialEq<T> for HashValue<str>
where
    T: AsRef<str>,
{
    fn eq(&self, other: &T) -> bool {
        self.0.eq(&hash::hash64(other.as_ref()))
    }
}

impl<T> PartialEq<T> for HashValue<Path>
where
    T: AsRef<Path>,
{
    fn eq(&self, other: &T) -> bool {
        self.0.eq(&hash::hash64(other.as_ref()))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::utils::hash::FastHashSet;

    #[test]
    fn hash_str() {
        let hash = HashValue::<str>::from("hash_str");
        assert_eq!(hash, "hash_str");
        assert!(hash != "other_str");
    }

    #[test]
    fn collections() {
        let mut set = FastHashSet::<HashValue<str>>::default();
        set.insert(HashValue::from("asdasd"));
        set.insert(HashValue::from("asdasd"));
        set.insert(HashValue::from("asdasd"));
        set.insert(HashValue::from("asdasd"));
        assert_eq!(set.len(), 1);
        assert_eq!(
            set.get(&("asdasd".into())),
            Some(&HashValue::from("asdasd"))
        );
    }

    #[test]
    fn hash_path() {
        let _ = HashValue::<Path>::from("str_path");
    }
}