lang-extension 1.3.0

Rust Lang Extension
Documentation
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

use super::*;

pub trait KeyConstraint: ValueConstraint + Eq + Hash {}

impl<T: ?Sized + ValueConstraint + Eq + Hash> KeyConstraint for T {}

pub trait Key: Value {
    fn hashcode(&self) -> u64 {
        self.memory_address() as u64
    }

    as_trait!(Key);
    as_boxed!(Key);
}

impl<T: ?Sized + KeyConstraint> Key for T {
    fn hashcode(&self) -> u64 {
        let mut hasher = DefaultHasher::default();
        self.hash(&mut hasher);
        hasher.finish()
    }

    as_trait!(impl Key);
    as_boxed!(impl Key);
}

#[macro_export]
macro_rules! boxed_key_trait {
    ($trait:tt) => {
as_boxed!(impl Eq for $trait);
as_boxed!(impl Hash for $trait);
boxed_value_trait!($trait);
    };

    ($trait:tt<$($param:tt), *>) => {
as_boxed!(impl Eq for $trait<$($param), *>);
as_boxed!(impl Hash for $trait<$($param), *>);
boxed_value_trait!($trait<$($param), *>);
    };

    ($trait:tt<$($param:tt: $constraint0:tt $(+ $constraint:tt)*), *>) => {
as_boxed!(impl Eq for $trait<$($param: $constraint0 $(+ $constraint)*), *>);
as_boxed!(impl Hash for $trait<$($param: $constraint0 $(+ $constraint)*), *>);
boxed_value_trait!($trait<$($param: $constraint0 $(+ $constraint)*), *>);
    };

    ($trait:tt<$($param:tt: ?Sized + $constraint0:tt $(+ $constraint:tt)*), *>) => {
as_boxed!(impl Eq for $trait<$($param: ?Sized + $constraint0 $(+ $constraint)*), *>);
as_boxed!(impl Hash for $trait<$($param: ?Sized + $constraint0 $(+ $constraint)*), *>);
boxed_value_trait!($trait<$($param: ?Sized + $constraint0 $(+ $constraint)*), *>);
    };

    ($trait:tt<$($param:tt: 'static + $constraint0:tt $(+ $constraint:tt)*), *>) => {
as_boxed!(impl Eq for $trait<$($param: 'static + $constraint0 $(+ $constraint)*), *>);
as_boxed!(impl Hash for $trait<$($param: 'static + $constraint0 $(+ $constraint)*), *>);
boxed_value_trait!($trait<$($param: 'static + $constraint0 $(+ $constraint)*), *>);
    };

    ($trait:tt<$($param:tt: 'static + ?Sized + $constraint0:tt $(+ $constraint:tt)*), *>) => {
as_boxed!(impl Eq for $trait<$($param: 'static + ?Sized + $constraint0 $(+ $constraint)*), *>);
as_boxed!(impl Hash for $trait<$($param: 'static + ?Sized + $constraint0 $(+ $constraint)*), *>);
boxed_value_trait!($trait<$($param: 'static + ?Sized + $constraint0 $(+ $constraint)*), *>);
    };
}

boxed_key_trait!(Key);

#[allow(dead_code)]
#[cfg(test)]
mod tests {

    use super::*;
    use crate::*;
    use std::collections::HashMap;
    use std::fmt::Debug;

    trait K1<K: KeyConstraint>: Key {
        fn say(&self, _k: K) {}

        as_boxed!(K1<K>);
    }

    #[derive(Hash, PartialEq, Eq, Debug, Clone)]
    struct S1 {
        a: i32,
        b: u32,
    }

    impl<K: KeyConstraint> K1<K> for S1 {
        as_boxed!(impl K1<K>);
    }

    boxed_key_trait!(K1<K: KeyConstraint>);

    #[test]
    fn hashcode() {
        let s = S1 { a: 1, b: 2 };
        assert_eq!(s.hashcode(), s.clone().hashcode());

        let bs: Box<dyn Key> = Box::new(s);
        assert_eq!(bs.hashcode(), bs.clone().hashcode());

        let mut hasher = DefaultHasher::new();
        bs.hash(&mut hasher);
        let _ = hasher.finish();
    }

    #[test]
    fn hashmap() {
        let k = S1 { a: 1, b: 2 };
        let v = S1 { a: 11, b: 22 };
        let key: Box<dyn Key> = Box::new(k.clone());
        let value: Box<dyn Value> = Box::new(v.clone());
        let mut map = HashMap::<Box<dyn Key>, Box<dyn Value>>::new();
        map.insert(key.clone(), value.clone());
        assert_eq!(&value, map.get(&key).unwrap());
    }

    trait SomeType0<K: KeyConstraint, V: ValueConstraint>: Key {
        fn say(&self, k: K, v: V);

        as_boxed!(SomeType0<K, V>);
        as_trait!(SomeType0<K, V>);
    }

    boxed_key_trait!(SomeType0<K: KeyConstraint, V: ValueConstraint>);

    trait SomeType1<K: KeyConstraint + Debug, V: ValueConstraint>: Key {
        fn say(&self, k: K, v: V);

        as_boxed!(SomeType1<K, V>);
        as_trait!(SomeType1<K, V>);
    }

    boxed_key_trait!(SomeType1<K: KeyConstraint + Debug, V: ValueConstraint>);

    trait SomeType2<K: ?Sized + KeyConstraint, V: ?Sized + ValueConstraint>: Key {
        fn say(&self, k: K, v: V);

        as_boxed!(SomeType2<K, V>);
        as_trait!(SomeType2<K, V>);
    }

    boxed_key_trait!(SomeType2<K: ?Sized + KeyConstraint, V: ?Sized + ValueConstraint>);

    trait SomeType3<K: 'static + KeyConstraint, V: 'static + ValueConstraint>: Key {
        fn say(&self, k: K, v: V);

        as_boxed!(SomeType3<K, V>);
        as_trait!(SomeType3<K, V>);
    }

    boxed_key_trait!(SomeType3<K: 'static + KeyConstraint, V: 'static + ValueConstraint>);

    trait SomeType4<K: 'static + ?Sized + KeyConstraint, V: 'static + ?Sized + ValueConstraint>:
        Key
    {
        fn say(&self, k: K, v: V);

        as_boxed!(SomeType4<K, V>);
        as_trait!(SomeType4<K, V>);
    }

    boxed_key_trait!(SomeType4<K: 'static + ?Sized + KeyConstraint, V: 'static + ?Sized + ValueConstraint>);
}