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