1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
//! The implementation for Version 1 [`Uuid`]s. //! //! Note that you need feature `v1` in order to use these features. //! //! [`Uuid`]: ../struct.Uuid.html use core::sync::atomic; use prelude::*; /// A thread-safe, stateful context for the v1 generator to help ensure /// process-wide uniqueness. #[derive(Debug)] pub struct Context { count: atomic::AtomicUsize, } /// A trait that abstracts over generation of Uuid v1 "Clock Sequence" values. pub trait ClockSequence { /// Return a 16-bit number that will be used as the "clock sequence" in /// the Uuid. The number must be different if the time has changed since /// the last time a clock sequence was requested. fn generate_sequence(&self, seconds: u64, nano_seconds: u32) -> u16; } impl Uuid { /// Create a new [`Uuid`] (version 1) using a time value + sequence + /// *NodeId*. /// /// This expects two values representing a monotonically increasing value /// as well as a unique 6 byte NodeId, and an implementation of /// [`ClockSequence`]. This function is only guaranteed to produce /// unique values if the following conditions hold: /// /// 1. The *NodeId* is unique for this process, /// 2. The *Context* is shared across all threads which are generating v1 /// [`Uuid`]s, /// 3. The [`ClockSequence`] implementation reliably returns unique /// clock sequences (this crate provides [`Context`] for this /// purpose. However you can create your own [`ClockSequence`] /// implementation, if [`Context`] does not meet your needs). /// /// The NodeID must be exactly 6 bytes long. If the NodeID is not a valid /// length this will return a [`ParseError`]`::InvalidLength`. /// /// The function is not guaranteed to produce monotonically increasing /// values however. There is a slight possibility that two successive /// equal time values could be supplied and the sequence counter wraps back /// over to 0. /// /// If uniqueness and monotonicity is required, the user is responsible for /// ensuring that the time value always increases between calls (including /// between restarts of the process and device). /// /// Note that usage of this method requires the `v1` feature of this crate /// to be enabled. /// /// # Examples /// /// Basic usage: /// /// ```rust /// use uuid::v1::Context; /// use uuid::Uuid; /// /// let context = Context::new(42); /// if let Ok(uuid) = /// Uuid::new_v1(&context, 1497624119, 1234, &[1, 2, 3, 4, 5, 6]) /// { /// assert_eq!( /// uuid.to_hyphenated().to_string(), /// "f3b4958c-52a1-11e7-802a-010203040506" /// ) /// } else { /// panic!() /// } /// ``` /// /// [`ParseError`]: ../enum.ParseError.html /// [`Uuid`]: ../struct.Uuid.html /// [`ClockSequence`]: struct.ClockSequence.html /// [`Context`]: struct.Context.html pub fn new_v1<T>( context: &T, seconds: u64, nano_seconds: u32, node_id: &[u8], ) -> Result<Self, ::BytesError> where T: ClockSequence, { const NODE_ID_LEN: usize = 6; let len = node_id.len(); if len != NODE_ID_LEN { return Err(::BytesError::new(NODE_ID_LEN, len)); } let time_low; let time_mid; let time_high_and_version; { /// The number of 100 ns ticks between the UUID epoch /// `1582-10-15 00:00:00` and the Unix epoch `1970-01-01 00:00:00`. const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000; let timestamp = seconds * 10_000_000 + u64::from(nano_seconds / 100); let uuid_time = timestamp + UUID_TICKS_BETWEEN_EPOCHS; time_low = (uuid_time & 0xFFFF_FFFF) as u32; time_mid = ((uuid_time >> 32) & 0xFFFF) as u16; time_high_and_version = (((uuid_time >> 48) & 0x0FFF) as u16) | (1 << 12); } let mut d4 = [0; 8]; { let count = context.generate_sequence(seconds, nano_seconds); d4[0] = (((count & 0x3F00) >> 8) as u8) | 0x80; d4[1] = (count & 0xFF) as u8; } d4[2..].copy_from_slice(node_id); Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4) } } impl Context { /// Creates a thread-safe, internally mutable context to help ensure /// uniqueness. /// /// This is a context which can be shared across threads. It maintains an /// internal counter that is incremented at every request, the value ends /// up in the clock_seq portion of the [`Uuid`] (the fourth group). This /// will improve the probability that the [`Uuid`] is unique across the /// process. /// /// [`Uuid`]: ../struct.Uuid.html pub fn new(count: u16) -> Self { Self { count: atomic::AtomicUsize::new(count as usize), } } } impl ClockSequence for Context { fn generate_sequence(&self, _: u64, _: u32) -> u16 { (self.count.fetch_add(1, atomic::Ordering::SeqCst) & 0xffff) as u16 } } #[cfg(test)] mod tests { #[test] fn test_new_v1() { use super::Context; use prelude::*; let time: u64 = 1_496_854_535; let time_fraction: u32 = 812_946_000; let node = [1, 2, 3, 4, 5, 6]; let context = Context::new(0); { let uuid = Uuid::new_v1(&context, time, time_fraction, &node).unwrap(); assert_eq!(uuid.get_version(), Some(Version::Mac)); assert_eq!(uuid.get_variant(), Some(Variant::RFC4122)); assert_eq!( uuid.to_hyphenated().to_string(), "20616934-4ba2-11e7-8000-010203040506" ); let ts = uuid.to_timestamp().unwrap(); assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460); assert_eq!(ts.1, 0); }; { let uuid2 = Uuid::new_v1(&context, time, time_fraction, &node).unwrap(); assert_eq!( uuid2.to_hyphenated().to_string(), "20616934-4ba2-11e7-8001-010203040506" ); assert_eq!(uuid2.to_timestamp().unwrap().1, 1) }; } }