1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#![feature(core_intrinsics)]
#![feature(plugin)]

#![cfg_attr(feature = "use_clippy", plugin(clippy))]
#![plugin(regex_macros)]

#![cfg_attr(feature = "use_clippy",
   warn(cast_possible_truncation, cast_possible_wrap, cast_precision_loss, cast_sign_loss,
        non_ascii_literal, shadow_same, string_add, string_add_assign, unicode_not_nfc))]

extern crate regex;
extern crate twox_hash;

use regex::Captures;
use std::hash::{Hash, Hasher};
use std::intrinsics;
use twox_hash::XxHash;

pub fn layout_id<T>() -> u64 {

    let mut s = XxHash::with_seed(0);
    
    get_type_name(unsafe { intrinsics::type_name::<T>() }).hash(&mut s);
    unsafe { intrinsics::min_align_of::<T>() }.hash(&mut s);
    unsafe { intrinsics::pref_align_of::<T>() }.hash(&mut s);
    unsafe { intrinsics::size_of::<T>() }.hash(&mut s);

    s.finish()
}

fn get_type_name(name: &str) -> String {

    let inner = regex!(r#"<(.*)>"#);
    let last_name = regex!(r#"[::]?([^:]*)$"#);

    let replaced_children = inner.replace_all(&name, |caps: &Captures| {
        format!("<{}>", get_type_name(&caps.at(1).unwrap()))
    });

    let caps = last_name.captures(&replaced_children).unwrap();

    String::from(caps.at(1).unwrap())
}

#[test]
fn test_get_type_name() {
    assert_eq!(&get_type_name("persistent_hashmap::HashmapEntry<user::User>"),
              "HashmapEntry<User>");
    assert_eq!(&get_type_name("persistent_hashmap::HashmapEntry<meus_iot::user::User>"),
               "HashmapEntry<User>");
    assert_eq!(&get_type_name("persistent_hashmap::HashmapEntry<meus_iot::user::User<test::Type>>"),
               "HashmapEntry<User<Type>>");
    assert_eq!(&get_type_name("HashmapEntry<User>"),
               "HashmapEntry<User>");
}