Skip to main content

ps_uuid/methods/
new_v2.rs

1use std::time::SystemTime;
2
3use crate::{UuidConstructionError, UUID};
4
5impl UUID {
6    /// Generate a v2 UUID from wall-clock time plus the extra DCE fields.
7    ///
8    /// # Errors
9    /// - `TimestampBeforeEpoch` is returned if `time` predates 1582-10-15.
10    /// - `TimestampOverflow` is returned if `time` exceeds 5236-03-31.
11    pub fn new_v2(
12        domain: u8,
13        local_id: u32,
14        time: SystemTime,
15        clock_seq: u16,
16        node_id: [u8; 6],
17    ) -> Result<Self, UuidConstructionError> {
18        let mut uuid = Self::new_v1(time, clock_seq, node_id)?;
19
20        uuid.bytes[0..4].copy_from_slice(&local_id.to_be_bytes());
21        uuid.bytes[9] = domain;
22
23        Ok(uuid.with_version(2))
24    }
25}
26
27#[cfg(test)]
28mod tests {
29    #![allow(clippy::expect_used)]
30    use std::time::{Duration, SystemTime};
31
32    use crate::{NodeId, UUID};
33
34    const fn variant_rfc_4122(byte: u8) -> bool {
35        (byte & 0b1100_0000) == 0b1000_0000
36    }
37
38    #[test]
39    fn new_v2_sets_local_id_and_domain() {
40        let domain = 3;
41        let local_id = 0xDEAD_BEEF;
42        let time = SystemTime::UNIX_EPOCH + Duration::from_secs(1);
43        let clock_seq = 0x1FFF;
44        let node_id = NodeId::random();
45
46        let u =
47            UUID::new_v2(domain, local_id, time, clock_seq, *node_id).expect("new_v2 must succeed");
48
49        // Same fixed-field checks as above
50        assert_eq!(&u.bytes[0..4], &local_id.to_be_bytes());
51        assert_eq!(u.bytes[9], domain);
52        assert!(variant_rfc_4122(u.bytes[8]));
53        assert_eq!(u.bytes[10..16], *node_id);
54        assert_eq!(u.get_version(), Some(2));
55    }
56
57    #[test]
58    fn new_v2_distinguishes_different_local_ids() {
59        let base_time = SystemTime::UNIX_EPOCH;
60        let node_id = NodeId::random();
61        let a = UUID::new_v2(0, 1, base_time, 1, *node_id)
62            .expect("new_v2 should succeed for valid inputs");
63        let b = UUID::new_v2(0, 2, base_time, 1, *node_id)
64            .expect("new_v2 should succeed for valid inputs");
65        assert_ne!(a.bytes, b.bytes);
66    }
67
68    #[test]
69    fn new_v2_distinguishes_different_domains() {
70        let base_time = SystemTime::UNIX_EPOCH;
71        let node_id = NodeId::random();
72        let a = UUID::new_v2(1, 0, base_time, 1, *node_id)
73            .expect("new_v2 should succeed for valid inputs");
74        let b = UUID::new_v2(2, 0, base_time, 1, *node_id)
75            .expect("new_v2 should succeed for valid inputs");
76        assert_ne!(a.bytes, b.bytes);
77    }
78}