simple_uuid/
name.rs

1#![cfg(any(feature = "hash_md5", feauture = "hash_sha1"))]
2
3use std::convert::TryInto;
4
5use md5;
6use sha1::Sha1;
7
8use crate::{Layout, Node, Variant, Version, UUID};
9
10impl Layout {
11    fn hash_fields(hash: [u8; 16], v: Version) -> Self {
12        Self {
13            field_low: ((hash[0] as u32) << 24)
14                | (hash[1] as u32) << 16
15                | (hash[2] as u32) << 8
16                | hash[3] as u32,
17            field_mid: (hash[4] as u16) << 8 | (hash[5] as u16),
18            field_high_and_version: ((hash[6] as u16) << 8 | (hash[7] as u16)) & 0xfff
19                | (v as u16) << 12,
20            clock_seq_high_and_reserved: (hash[8] & 0xf) | (Variant::RFC as u8) << 4,
21            clock_seq_low: hash[9] as u8,
22            node: Node([hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]]),
23        }
24    }
25}
26
27impl UUID {
28    /// New UUID version-3 using md5 algorithme
29    #[doc(cfg(feature = "hash_md5"))]
30    pub fn using_md5(data: &str, ns: UUID) -> Layout {
31        let hash = md5::compute(Self::concat(data, ns)).0;
32        Layout::hash_fields(hash, Version::MD5)
33    }
34
35    /// New UUID version-5 using sha1 algorithme
36    #[doc(cfg(feature = "hash_sha1"))]
37    pub fn using_sha1(data: &str, ns: UUID) -> Layout {
38        let hash = Sha1::from(Self::concat(data, ns)).digest().bytes()[..16]
39            .try_into()
40            .unwrap();
41        Layout::hash_fields(hash, Version::SHA1)
42    }
43
44    fn concat(data: &str, ns: UUID) -> String {
45        format!("{:x}", ns) + data
46    }
47}
48
49impl ToString for Layout {
50    fn to_string(&self) -> String {
51        format!("{:02x}", self.as_bytes(),)
52    }
53}
54
55/// `UUID` version-3
56#[doc(cfg(feature = "hash_md5"))]
57#[macro_export]
58macro_rules! v3 {
59    ($data:expr, $ns:expr) => {
60        format!("{:x}", $crate::UUID::using_md5($data, $ns).as_bytes())
61    };
62}
63
64/// `UUID` version-5
65#[doc(cfg(feature = "hash_sha1"))]
66#[macro_export]
67macro_rules! v5 {
68    ($data:expr, $ns:expr) => {
69        format!("{:x}", $crate::UUID::using_sha1($data, $ns).as_bytes())
70    };
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn new_uuid_using_md5() {
79        let ns = [
80            UUID::NAMESPACE_DNS,
81            UUID::NAMESPACE_OID,
82            UUID::NAMESPACE_URL,
83            UUID::NAMESPACE_X500,
84        ];
85
86        for s in ns.iter() {
87            assert_eq!(
88                UUID::using_md5("test_data", *s).get_version(),
89                Some(Version::MD5)
90            );
91            assert_eq!(
92                UUID::using_md5("test_data", *s).get_variant(),
93                Some(Variant::RFC)
94            );
95        }
96    }
97
98    #[test]
99    fn new_uuid_using_sha1() {
100        let ns = [
101            UUID::NAMESPACE_DNS,
102            UUID::NAMESPACE_OID,
103            UUID::NAMESPACE_URL,
104            UUID::NAMESPACE_X500,
105        ];
106
107        for s in ns.iter() {
108            assert_eq!(
109                UUID::using_sha1("test_data", *s).get_version(),
110                Some(Version::SHA1)
111            );
112            assert_eq!(
113                UUID::using_sha1("test_data", *s).get_variant(),
114                Some(Variant::RFC)
115            );
116        }
117    }
118}