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 #[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 #[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#[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#[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}