1 //! The implementation for Version 1 UUIDs. 2 //! 3 //! Note that you need feature `v1` in order to use these features. 4 5 use crate::prelude::*; 6 use core::sync::atomic; 7 8 /// The number of 100 ns ticks between the UUID epoch 9 /// `1582-10-15 00:00:00` and the Unix epoch `1970-01-01 00:00:00`. 10 const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000; 11 12 /// A thread-safe, stateful context for the v1 generator to help ensure 13 /// process-wide uniqueness. 14 #[derive(Debug)] 15 pub struct Context { 16 count: atomic::AtomicUsize, 17 } 18 19 /// Stores the number of nanoseconds from an epoch and a counter for ensuring 20 /// V1 ids generated on the same host are unique. 21 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 22 pub struct Timestamp { 23 ticks: u64, 24 counter: u16, 25 } 26 27 impl Timestamp { 28 /// Construct a `Timestamp` from its raw component values: an RFC4122 29 /// timestamp and counter. 30 /// 31 /// RFC4122, which defines the V1 UUID, specifies a 60-byte timestamp format 32 /// as the number of 100-nanosecond intervals elapsed since 00:00:00.00, 33 /// 15 Oct 1582, "the date of the Gregorian reform of the Christian 34 /// calendar." 35 /// 36 /// The counter value is used to differentiate between ids generated by 37 /// the same host computer in rapid succession (i.e. with the same observed 38 /// time). See the [`ClockSequence`] trait for a generic interface to any 39 /// counter generators that might be used. 40 /// 41 /// Internally, the timestamp is stored as a `u64`. For this reason, dates 42 /// prior to October 1582 are not supported. 43 /// 44 /// [`ClockSequence`]: trait.ClockSequence.html from_rfc4122(ticks: u64, counter: u16) -> Self45 pub const fn from_rfc4122(ticks: u64, counter: u16) -> Self { 46 Timestamp { ticks, counter } 47 } 48 49 /// Construct a `Timestamp` from a unix timestamp and sequence-generating 50 /// `context`. 51 /// 52 /// A unix timestamp represents the elapsed time since Jan 1 1970. Libc's 53 /// `clock_gettime` and other popular implementations traditionally 54 /// represent this duration as a `timespec`: a struct with `u64` and 55 /// `u32` fields representing the seconds, and "subsecond" or fractional 56 /// nanoseconds elapsed since the timestamp's second began, 57 /// respectively. 58 /// 59 /// This constructs a `Timestamp` from the seconds and fractional 60 /// nanoseconds of a unix timestamp, converting the duration since 1970 61 /// into the number of 100-nanosecond intervals since 00:00:00.00, 15 62 /// Oct 1582 specified by RFC4122 and used internally by `Timestamp`. 63 /// 64 /// The function is not guaranteed to produce monotonically increasing 65 /// values however. There is a slight possibility that two successive 66 /// equal time values could be supplied and the sequence counter wraps back 67 /// over to 0. 68 /// 69 /// If uniqueness and monotonicity is required, the user is responsible for 70 /// ensuring that the time value always increases between calls (including 71 /// between restarts of the process and device). from_unix( context: impl ClockSequence, seconds: u64, subsec_nanos: u32, ) -> Self72 pub fn from_unix( 73 context: impl ClockSequence, 74 seconds: u64, 75 subsec_nanos: u32, 76 ) -> Self { 77 let counter = context.generate_sequence(seconds, subsec_nanos); 78 let ticks = UUID_TICKS_BETWEEN_EPOCHS 79 + seconds * 10_000_000 80 + u64::from(subsec_nanos) / 100; 81 82 Timestamp { ticks, counter } 83 } 84 85 /// Returns the raw RFC4122 timestamp and counter values stored by the 86 /// `Timestamp`. 87 /// 88 /// The timestamp (the first, `u64` element in the tuple) represents the 89 /// number of 100-nanosecond intervals since 00:00:00.00, 15 Oct 1582. 90 /// The counter is used to differentiate between ids generated on the 91 /// same host computer with the same observed time. to_rfc4122(&self) -> (u64, u16)92 pub const fn to_rfc4122(&self) -> (u64, u16) { 93 (self.ticks, self.counter) 94 } 95 96 /// Returns the timestamp converted to the seconds and fractional 97 /// nanoseconds since Jan 1 1970. 98 /// 99 /// Internally, the time is stored in 100-nanosecond intervals, 100 /// thus the maximum precision represented by the fractional nanoseconds 101 /// value is less than its unit size (100 ns vs. 1 ns). to_unix(&self) -> (u64, u32)102 pub const fn to_unix(&self) -> (u64, u32) { 103 ( 104 (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) / 10_000_000, 105 ((self.ticks - UUID_TICKS_BETWEEN_EPOCHS) % 10_000_000) as u32 106 * 100, 107 ) 108 } 109 110 /// Returns the timestamp converted into nanoseconds elapsed since Jan 1 111 /// 1970. Internally, the time is stored in 100-nanosecond intervals, 112 /// thus the maximum precision represented is less than the units it is 113 /// measured in (100 ns vs. 1 ns). The value returned represents the 114 /// same duration as [`Timestamp::to_unix`]; this provides it in nanosecond 115 /// units for convenience. to_unix_nanos(&self) -> u64116 pub const fn to_unix_nanos(&self) -> u64 { 117 (self.ticks - UUID_TICKS_BETWEEN_EPOCHS) * 100 118 } 119 } 120 121 /// A trait that abstracts over generation of UUID v1 "Clock Sequence" values. 122 pub trait ClockSequence { 123 /// Return a 16-bit number that will be used as the "clock sequence" in 124 /// the UUID. The number must be different if the time has changed since 125 /// the last time a clock sequence was requested. generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16126 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16; 127 } 128 129 impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T { generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16130 fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> u16 { 131 (**self).generate_sequence(seconds, subsec_nanos) 132 } 133 } 134 135 impl Uuid { 136 /// Create a new UUID (version 1) using a time value + sequence + 137 /// *NodeId*. 138 /// 139 /// When generating [`Timestamp`]s using a [`ClockSequence`], this function 140 /// is only guaranteed to produce unique values if the following conditions 141 /// hold: 142 /// 143 /// 1. The *NodeId* is unique for this process, 144 /// 2. The *Context* is shared across all threads which are generating v1 145 /// UUIDs, 146 /// 3. The [`ClockSequence`] implementation reliably returns unique 147 /// clock sequences (this crate provides [`Context`] for this 148 /// purpose. However you can create your own [`ClockSequence`] 149 /// implementation, if [`Context`] does not meet your needs). 150 /// 151 /// The NodeID must be exactly 6 bytes long. 152 /// 153 /// Note that usage of this method requires the `v1` feature of this crate 154 /// to be enabled. 155 /// 156 /// # Examples 157 /// 158 /// A UUID can be created from a unix [`Timestamp`] with a 159 /// [`ClockSequence`]: 160 /// 161 /// ```rust 162 /// use uuid::v1::{Timestamp, Context}; 163 /// use uuid::Uuid; 164 /// 165 /// let context = Context::new(42); 166 /// let ts = Timestamp::from_unix(&context, 1497624119, 1234); 167 /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]).expect("failed to generate UUID"); 168 /// 169 /// assert_eq!( 170 /// uuid.to_hyphenated().to_string(), 171 /// "f3b4958c-52a1-11e7-802a-010203040506" 172 /// ); 173 /// ``` 174 /// 175 /// The timestamp can also be created manually as per RFC4122: 176 /// 177 /// ``` 178 /// use uuid::v1::{Timestamp, Context}; 179 /// use uuid::Uuid; 180 /// 181 /// let context = Context::new(42); 182 /// let ts = Timestamp::from_rfc4122(1497624119, 0); 183 /// let uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]).expect("failed to generate UUID"); 184 /// 185 /// assert_eq!( 186 /// uuid.to_hyphenated().to_string(), 187 /// "5943ee37-0000-1000-8000-010203040506" 188 /// ); 189 /// ``` 190 /// 191 /// [`Timestamp`]: v1/struct.Timestamp.html 192 /// [`ClockSequence`]: v1/struct.ClockSequence.html 193 /// [`Context`]: v1/struct.Context.html new_v1(ts: Timestamp, node_id: &[u8]) -> Result<Self, crate::Error>194 pub fn new_v1(ts: Timestamp, node_id: &[u8]) -> Result<Self, crate::Error> { 195 const NODE_ID_LEN: usize = 6; 196 197 let len = node_id.len(); 198 if len != NODE_ID_LEN { 199 Err(crate::builder::Error::new(NODE_ID_LEN, len))?; 200 } 201 202 let time_low = (ts.ticks & 0xFFFF_FFFF) as u32; 203 let time_mid = ((ts.ticks >> 32) & 0xFFFF) as u16; 204 let time_high_and_version = 205 (((ts.ticks >> 48) & 0x0FFF) as u16) | (1 << 12); 206 207 let mut d4 = [0; 8]; 208 209 { 210 d4[0] = (((ts.counter & 0x3F00) >> 8) as u8) | 0x80; 211 d4[1] = (ts.counter & 0xFF) as u8; 212 } 213 214 d4[2..].copy_from_slice(node_id); 215 216 Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4) 217 } 218 219 /// Returns an optional [`Timestamp`] storing the timestamp and 220 /// counter portion parsed from a V1 UUID. 221 /// 222 /// Returns `None` if the supplied UUID is not V1. 223 /// 224 /// The V1 timestamp format defined in RFC4122 specifies a 60-bit 225 /// integer representing the number of 100-nanosecond intervals 226 /// since 00:00:00.00, 15 Oct 1582. 227 /// 228 /// [`Timestamp`] offers several options for converting the raw RFC4122 229 /// value into more commonly-used formats, such as a unix timestamp. 230 /// 231 /// [`Timestamp`]: v1/struct.Timestamp.html to_timestamp(&self) -> Option<Timestamp>232 pub fn to_timestamp(&self) -> Option<Timestamp> { 233 if self 234 .get_version() 235 .map(|v| v != Version::Mac) 236 .unwrap_or(true) 237 { 238 return None; 239 } 240 241 let ticks: u64 = u64::from(self.as_bytes()[6] & 0x0F) << 56 242 | u64::from(self.as_bytes()[7]) << 48 243 | u64::from(self.as_bytes()[4]) << 40 244 | u64::from(self.as_bytes()[5]) << 32 245 | u64::from(self.as_bytes()[0]) << 24 246 | u64::from(self.as_bytes()[1]) << 16 247 | u64::from(self.as_bytes()[2]) << 8 248 | u64::from(self.as_bytes()[3]); 249 250 let counter: u16 = u16::from(self.as_bytes()[8] & 0x3F) << 8 251 | u16::from(self.as_bytes()[9]); 252 253 Some(Timestamp::from_rfc4122(ticks, counter)) 254 } 255 } 256 257 impl Context { 258 /// Creates a thread-safe, internally mutable context to help ensure 259 /// uniqueness. 260 /// 261 /// This is a context which can be shared across threads. It maintains an 262 /// internal counter that is incremented at every request, the value ends 263 /// up in the clock_seq portion of the UUID (the fourth group). This 264 /// will improve the probability that the UUID is unique across the 265 /// process. new(count: u16) -> Self266 pub const fn new(count: u16) -> Self { 267 Self { 268 count: atomic::AtomicUsize::new(count as usize), 269 } 270 } 271 } 272 273 impl ClockSequence for Context { generate_sequence(&self, _: u64, _: u32) -> u16274 fn generate_sequence(&self, _: u64, _: u32) -> u16 { 275 (self.count.fetch_add(1, atomic::Ordering::SeqCst) & 0xffff) as u16 276 } 277 } 278 279 #[cfg(test)] 280 mod tests { 281 use super::*; 282 283 use crate::std::string::ToString; 284 285 #[test] test_new_v1()286 fn test_new_v1() { 287 let time: u64 = 1_496_854_535; 288 let time_fraction: u32 = 812_946_000; 289 let node = [1, 2, 3, 4, 5, 6]; 290 let context = Context::new(0); 291 292 { 293 let uuid = Uuid::new_v1( 294 Timestamp::from_unix(&context, time, time_fraction), 295 &node, 296 ) 297 .unwrap(); 298 299 assert_eq!(uuid.get_version(), Some(Version::Mac)); 300 assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); 301 assert_eq!( 302 uuid.to_hyphenated().to_string(), 303 "20616934-4ba2-11e7-8000-010203040506" 304 ); 305 306 let ts = uuid.to_timestamp().unwrap().to_rfc4122(); 307 308 assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460); 309 assert_eq!(ts.1, 0); 310 }; 311 312 { 313 let uuid2 = Uuid::new_v1( 314 Timestamp::from_unix(&context, time, time_fraction), 315 &node, 316 ) 317 .unwrap(); 318 319 assert_eq!( 320 uuid2.to_hyphenated().to_string(), 321 "20616934-4ba2-11e7-8001-010203040506" 322 ); 323 assert_eq!(uuid2.to_timestamp().unwrap().to_rfc4122().1, 1) 324 }; 325 } 326 } 327