Skip to main content

ps_uuid/methods/
from_parts_dcom.rs

1use crate::{Variant, UUID};
2
3impl UUID {
4    /// Creates a new DCOM UUID with the specified `time_low`, `time_mid`, `time_hi_and_version`,
5    /// `clock_seq`, and node fields.
6    ///
7    /// # Arguments
8    /// * `time_low` - The low field of the timestamp (32 bits)
9    /// * `time_mid` - The middle field of the timestamp (16 bits)
10    /// * `time_hi_and_version` - The high field of the timestamp and version (16 bits)
11    /// * `clock_seq` - The clock sequence (14 bits, but passed as 16 bits)
12    /// * `node` - The node ID (48 bits, passed as 6 bytes)
13    ///
14    /// # Returns
15    /// A UUID with the DCOM variant (0b110) set
16    #[must_use]
17    pub fn from_parts_dcom(
18        time_low: u32,
19        time_mid: u16,
20        time_hi_and_version: u16,
21        clock_seq: u16,
22        node: [u8; 6],
23    ) -> Self {
24        let mut uuid = Self::nil();
25
26        // Set time_low (first 4 bytes, little-endian)
27        uuid.bytes[0..4].copy_from_slice(&time_low.to_le_bytes());
28
29        // Set time_mid (next 2 bytes, little-endian)
30        uuid.bytes[4..6].copy_from_slice(&time_mid.to_le_bytes());
31
32        // Set time_hi_and_version (next 2 bytes, little-endian)
33        uuid.bytes[6..8].copy_from_slice(&time_hi_and_version.to_le_bytes());
34
35        // Set clock_seq (next 2 bytes, little-endian)
36        uuid.bytes[8..10].copy_from_slice(&clock_seq.to_be_bytes());
37
38        // Set node (last 6 bytes)
39        uuid.bytes[10..16].copy_from_slice(&node);
40
41        // Set DCOM variant (0b110 in bits 7-5 of byte 8)
42        uuid.with_variant(Variant::DCOM)
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    #![allow(clippy::expect_used)]
49    use super::*;
50
51    #[test]
52    fn test_new_dcom_from_parts_uuid() {
53        let uuid = UUID::from_parts_dcom(
54            0x1234_5678,
55            0x9ABC,
56            0xDEF0,
57            0x1234,
58            [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF],
59        );
60
61        let expected_bytes = [
62            0x78, 0x56, 0x34, 0x12, // time_low (little-endian)
63            0xBC, 0x9A, // time_mid (little-endian)
64            0xF0, 0xDE, // time_hi_and_version (little-endian)
65            0xD2, 0x34, // clock_seq (big-endian, with variant 0b110)
66            0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, // node
67        ];
68
69        assert_eq!(uuid.bytes, expected_bytes);
70    }
71
72    #[test]
73    fn test_dcom_variant() {
74        let uuid = UUID::from_parts_dcom(
75            0,      // time_low
76            0,      // time_mid
77            0,      // time_hi_and_version
78            0,      // clock_seq
79            [0; 6], // node
80        );
81
82        // Check variant bits (byte 8, bits 7-5 should be 0b110)
83        let variant_bits = (uuid.bytes[8] & 0xE0) >> 5;
84        assert_eq!(variant_bits, 0x06); // 0b110
85    }
86
87    #[test]
88    fn test_nil_uuid() {
89        let nil_uuid = UUID::nil();
90        assert_eq!(nil_uuid.bytes, [0; 16]);
91    }
92
93    #[test]
94    #[allow(clippy::unwrap_used)]
95    fn test_dcom_uuid_fields_preservation() {
96        let time_low = 0x1234_5678;
97        let time_mid = 0x9ABC;
98        let time_hi_and_version = 0xDEF0;
99        let clock_seq = 0x1234;
100        let node = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF];
101
102        let uuid = UUID::from_parts_dcom(time_low, time_mid, time_hi_and_version, clock_seq, node);
103
104        // Verify each field
105        assert_eq!(
106            u32::from_le_bytes(
107                uuid.bytes[0..4]
108                    .try_into()
109                    .expect("UUID byte slice should match expected field length")
110            ),
111            time_low
112        );
113        assert_eq!(
114            u16::from_le_bytes(
115                uuid.bytes[4..6]
116                    .try_into()
117                    .expect("UUID byte slice should match expected field length")
118            ),
119            time_mid
120        );
121        assert_eq!(
122            u16::from_le_bytes(
123                uuid.bytes[6..8]
124                    .try_into()
125                    .expect("UUID byte slice should match expected field length")
126            ),
127            time_hi_and_version
128        );
129        assert_eq!(uuid.bytes[10..16], node);
130    }
131
132    #[test]
133    fn test_dcom_uuid_variant_preservation() {
134        // Create a UUID with a clock_seq that might interfere with variant bits
135        let uuid = UUID::from_parts_dcom(
136            0, 0, 0, 0xFFFF, // clock_seq with all bits set
137            [0; 6],
138        );
139
140        // Verify variant is still DCOM (0b110)
141        let variant_bits = (uuid.bytes[8] & 0xE0) >> 5;
142        assert_eq!(variant_bits, 0x06); // 0b110
143    }
144
145    #[test]
146    fn test_dcom_uuid_zero_values() {
147        let uuid = UUID::from_parts_dcom(0, 0, 0, 0, [0; 6]);
148
149        // Should be all zeros except for variant bits
150        let mut expected = [0; 16];
151        expected[8] = 0xC0; // Variant bits set to 0b110
152
153        assert_eq!(uuid.bytes, expected);
154    }
155
156    #[test]
157    fn test_dcom_uuid_max_values() {
158        let uuid = UUID::from_parts_dcom(u32::MAX, u16::MAX, u16::MAX, u16::MAX, [0xFF; 6]);
159
160        let expected = [
161            0xFF, 0xFF, 0xFF, 0xFF, // time_low
162            0xFF, 0xFF, // time_mid
163            0xFF, 0xFF, // time_hi_and_version
164            0xDF, 0xFF, // clock_seq (variant will modify MSB to 0b110)
165            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // node
166        ];
167
168        assert_eq!(uuid.bytes, expected);
169    }
170
171    #[test]
172    fn test_new_dcom_from_parts_valid_input() {
173        let time_low = 0x1234_5678;
174        let time_mid = 0xABCD;
175        let time_hi_and_version = 0x1FFF; // Version 1 for DCOM
176        let clock_seq = 0xEFFF;
177        let node = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB];
178
179        let uuid = UUID::from_parts_dcom(time_low, time_mid, time_hi_and_version, clock_seq, node);
180
181        // Expected byte layout for DCOM UUID (little-endian for first three fields)
182        let expected_bytes = [
183            0x78, 0x56, 0x34, 0x12, // time_low
184            0xCD, 0xAB, // time_mid
185            0xFF, 0x1F, // time_hi_and_version
186            0xCF, 0xFF, // clock_seq
187            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, // node
188        ];
189
190        assert_eq!(uuid.bytes, expected_bytes);
191    }
192
193    #[test]
194    fn test_new_dcom_from_parts_zero_input() {
195        let time_low = 0;
196        let time_mid = 0;
197        let time_hi_and_version = 0;
198        let clock_seq = 0;
199        let node = [0; 6];
200
201        let uuid = UUID::from_parts_dcom(time_low, time_mid, time_hi_and_version, clock_seq, node);
202
203        assert_eq!(uuid, UUID::nil().with_variant(Variant::DCOM));
204    }
205
206    #[test]
207    fn test_new_dcom_from_parts_max_input() {
208        let time_low = u32::MAX;
209        let time_mid = u16::MAX;
210        let time_hi_and_version = u16::MAX;
211        let clock_seq = u16::MAX;
212        let node = [0xFF; 6];
213
214        let uuid = UUID::from_parts_dcom(time_low, time_mid, time_hi_and_version, clock_seq, node);
215
216        assert_eq!(uuid, UUID::max().with_variant(Variant::DCOM));
217    }
218
219    #[test]
220    fn test_new_dcom_from_parts_endianness() {
221        let time_low = 0x1122_3344;
222        let time_mid = 0x5566;
223        let time_hi_and_version = 0x7788;
224        let clock_seq = 0x99AA;
225        let node = [0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00];
226
227        let uuid = UUID::from_parts_dcom(time_low, time_mid, time_hi_and_version, clock_seq, node);
228
229        // Check little-endian for time_low, time_mid, time_hi_and_version
230        assert_eq!(uuid.bytes[0..4], [0x44, 0x33, 0x22, 0x11]); // time_low
231        assert_eq!(uuid.bytes[4..6], [0x66, 0x55]); // time_mid
232        assert_eq!(uuid.bytes[6..8], [0x88, 0x77]); // time_hi_and_version
233                                                    // Check big-endian for clock_seq and node
234        assert_eq!(uuid.bytes[8..10], [0xD9, 0xAA]); // clock_seq
235        assert_eq!(uuid.bytes[10..16], [0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00]); // node
236    }
237}