1 //! The implementation for Version 6 UUIDs. 2 //! 3 //! Note that you need to enable the `v6` Cargo feature 4 //! in order to use this module. 5 6 use crate::{Builder, Timestamp, Uuid}; 7 8 impl Uuid { 9 /// Create a new version 6 UUID using the current system time and node ID. 10 /// 11 /// This method is only available if the `std` feature is enabled. 12 /// 13 /// This method is a convenient alternative to [`Uuid::new_v6`] that uses the current system time 14 /// as the source timestamp. 15 /// 16 /// Note that usage of this method requires the `v6`, `std`, and `rng` features of this crate 17 /// to be enabled. 18 #[cfg(all(feature = "std", feature = "rng"))] now_v6(node_id: &[u8; 6]) -> Self19 pub fn now_v6(node_id: &[u8; 6]) -> Self { 20 let ts = Timestamp::now(crate::timestamp::context::shared_context()); 21 22 Self::new_v6(ts, node_id) 23 } 24 25 /// Create a new version 6 UUID using the given timestamp and a node ID. 26 /// 27 /// This is similar to version 1 UUIDs, except that it is lexicographically sortable by timestamp. 28 /// 29 /// Also see [`Uuid::now_v6`] for a convenient way to generate version 6 30 /// UUIDs using the current system time. 31 /// 32 /// When generating [`Timestamp`]s using a [`ClockSequence`], this function 33 /// is only guaranteed to produce unique values if the following conditions 34 /// hold: 35 /// 36 /// 1. The *node ID* is unique for this process, 37 /// 2. The *context* is shared across all threads which are generating version 6 38 /// UUIDs, 39 /// 3. The [`ClockSequence`] implementation reliably returns unique 40 /// clock sequences (this crate provides [`Context`] for this 41 /// purpose. However you can create your own [`ClockSequence`] 42 /// implementation, if [`Context`] does not meet your needs). 43 /// 44 /// The NodeID must be exactly 6 bytes long. 45 /// 46 /// Note that usage of this method requires the `v6` feature of this crate 47 /// to be enabled. 48 /// 49 /// # Examples 50 /// 51 /// A UUID can be created from a unix [`Timestamp`] with a 52 /// [`ClockSequence`]. RFC4122 requires the clock sequence 53 /// is seeded with a random value: 54 /// 55 /// ```rust 56 /// # use uuid::{Uuid, Timestamp, Context}; 57 /// # fn random_seed() -> u16 { 42 } 58 /// let context = Context::new(random_seed()); 59 /// let ts = Timestamp::from_unix(context, 1497624119, 1234); 60 /// 61 /// let uuid = Uuid::new_v6(ts, &[1, 2, 3, 4, 5, 6]); 62 /// 63 /// assert_eq!( 64 /// uuid.hyphenated().to_string(), 65 /// "1e752a1f-3b49-658c-802a-010203040506" 66 /// ); 67 /// ``` 68 /// 69 /// The timestamp can also be created manually as per RFC4122: 70 /// 71 /// ``` 72 /// # use uuid::{Uuid, Timestamp, Context, ClockSequence}; 73 /// # fn random_seed() -> u16 { 42 } 74 /// let context = Context::new(random_seed()); 75 /// let ts = Timestamp::from_rfc4122(14976241191231231313, context.generate_sequence(0, 0) ); 76 /// 77 /// let uuid = Uuid::new_v6(ts, &[1, 2, 3, 4, 5, 6]); 78 /// 79 /// assert_eq!( 80 /// uuid.hyphenated().to_string(), 81 /// "fd64c041-1e91-6551-802a-010203040506" 82 /// ); 83 /// ``` 84 /// 85 /// # References 86 /// 87 /// * [Version 6 UUIDs in Draft RFC: New UUID Formats, Version 4](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1) 88 /// 89 /// [`Timestamp`]: timestamp/struct.Timestamp.html 90 /// [`ClockSequence`]: timestamp/trait.ClockSequence.html 91 /// [`Context`]: timestamp/context/struct.Context.html new_v6(ts: Timestamp, node_id: &[u8; 6]) -> Self92 pub fn new_v6(ts: Timestamp, node_id: &[u8; 6]) -> Self { 93 let (ticks, counter) = ts.to_rfc4122(); 94 95 Builder::from_sorted_rfc4122_timestamp(ticks, counter, node_id).into_uuid() 96 } 97 } 98 99 #[cfg(test)] 100 mod tests { 101 use super::*; 102 use crate::{Context, Variant, Version}; 103 use std::string::ToString; 104 105 #[cfg(all( 106 target_arch = "wasm32", 107 target_vendor = "unknown", 108 target_os = "unknown" 109 ))] 110 use wasm_bindgen_test::*; 111 112 #[test] 113 #[cfg_attr( 114 all( 115 target_arch = "wasm32", 116 target_vendor = "unknown", 117 target_os = "unknown" 118 ), 119 wasm_bindgen_test 120 )] test_new()121 fn test_new() { 122 let time: u64 = 1_496_854_535; 123 let time_fraction: u32 = 812_946_000; 124 let node = [1, 2, 3, 4, 5, 6]; 125 let context = Context::new(0); 126 127 let uuid = Uuid::new_v6(Timestamp::from_unix(context, time, time_fraction), &node); 128 129 assert_eq!(uuid.get_version(), Some(Version::SortMac)); 130 assert_eq!(uuid.get_variant(), Variant::RFC4122); 131 assert_eq!( 132 uuid.hyphenated().to_string(), 133 "1e74ba22-0616-6934-8000-010203040506" 134 ); 135 136 let ts = uuid.get_timestamp().unwrap().to_rfc4122(); 137 138 assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460); 139 140 // Ensure parsing the same UUID produces the same timestamp 141 let parsed = Uuid::parse_str("1e74ba22-0616-6934-8000-010203040506").unwrap(); 142 143 assert_eq!( 144 uuid.get_timestamp().unwrap(), 145 parsed.get_timestamp().unwrap() 146 ); 147 } 148 149 #[test] 150 #[cfg_attr( 151 all( 152 target_arch = "wasm32", 153 target_vendor = "unknown", 154 target_os = "unknown" 155 ), 156 wasm_bindgen_test 157 )] 158 #[cfg(all(feature = "std", feature = "rng"))] test_now()159 fn test_now() { 160 let node = [1, 2, 3, 4, 5, 6]; 161 162 let uuid = Uuid::now_v6(&node); 163 164 assert_eq!(uuid.get_version(), Some(Version::SortMac)); 165 assert_eq!(uuid.get_variant(), Variant::RFC4122); 166 } 167 168 #[test] 169 #[cfg_attr( 170 all( 171 target_arch = "wasm32", 172 target_vendor = "unknown", 173 target_os = "unknown" 174 ), 175 wasm_bindgen_test 176 )] test_new_context()177 fn test_new_context() { 178 let time: u64 = 1_496_854_535; 179 let time_fraction: u32 = 812_946_000; 180 let node = [1, 2, 3, 4, 5, 6]; 181 182 // This context will wrap 183 let context = Context::new(u16::MAX >> 2); 184 185 let uuid1 = Uuid::new_v6(Timestamp::from_unix(&context, time, time_fraction), &node); 186 187 let time: u64 = 1_496_854_536; 188 189 let uuid2 = Uuid::new_v6(Timestamp::from_unix(&context, time, time_fraction), &node); 190 191 assert_eq!(uuid1.get_timestamp().unwrap().to_rfc4122().1, 16383); 192 assert_eq!(uuid2.get_timestamp().unwrap().to_rfc4122().1, 0); 193 194 let time = 1_496_854_535; 195 196 let uuid3 = Uuid::new_v6(Timestamp::from_unix(&context, time, time_fraction), &node); 197 let uuid4 = Uuid::new_v6(Timestamp::from_unix(&context, time, time_fraction), &node); 198 199 assert_eq!(uuid3.get_timestamp().unwrap().counter, 1); 200 assert_eq!(uuid4.get_timestamp().unwrap().counter, 2); 201 } 202 } 203