uuid/v6.rs
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
6use crate::{Builder, Timestamp, Uuid};
7
8impl 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"))]
19 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`]. RFC 9562 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 RFC 9562:
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_gregorian(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 /// * [UUID Version 6 in RFC 9562](https://www.ietf.org/rfc/rfc9562.html#section-5.6)
88 ///
89 /// [`Timestamp`]: timestamp/struct.Timestamp.html
90 /// [`ClockSequence`]: timestamp/trait.ClockSequence.html
91 /// [`Context`]: timestamp/context/struct.Context.html
92 pub fn new_v6(ts: Timestamp, node_id: &[u8; 6]) -> Self {
93 let (ticks, counter) = ts.to_gregorian();
94
95 Builder::from_sorted_gregorian_timestamp(ticks, counter, node_id).into_uuid()
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::{Context, Variant, Version};
103 use std::string::ToString;
104
105 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
106 use wasm_bindgen_test::*;
107
108 #[test]
109 #[cfg_attr(
110 all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
111 wasm_bindgen_test
112 )]
113 fn test_new() {
114 let time: u64 = 1_496_854_535;
115 let time_fraction: u32 = 812_946_000;
116 let node = [1, 2, 3, 4, 5, 6];
117 let context = Context::new(0);
118
119 let uuid = Uuid::new_v6(Timestamp::from_unix(context, time, time_fraction), &node);
120
121 assert_eq!(uuid.get_version(), Some(Version::SortMac));
122 assert_eq!(uuid.get_variant(), Variant::RFC4122);
123 assert_eq!(
124 uuid.hyphenated().to_string(),
125 "1e74ba22-0616-6934-8000-010203040506"
126 );
127
128 let ts = uuid.get_timestamp().unwrap().to_gregorian();
129
130 assert_eq!(ts.0 - 0x01B2_1DD2_1381_4000, 14_968_545_358_129_460);
131
132 assert_eq!(Some(node), uuid.get_node_id(),);
133
134 // Ensure parsing the same UUID produces the same timestamp
135 let parsed = Uuid::parse_str("1e74ba22-0616-6934-8000-010203040506").unwrap();
136
137 assert_eq!(
138 uuid.get_timestamp().unwrap(),
139 parsed.get_timestamp().unwrap()
140 );
141
142 assert_eq!(uuid.get_node_id().unwrap(), parsed.get_node_id().unwrap(),);
143 }
144
145 #[test]
146 #[cfg_attr(
147 all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
148 wasm_bindgen_test
149 )]
150 #[cfg(all(feature = "std", feature = "rng"))]
151 fn test_now() {
152 let node = [1, 2, 3, 4, 5, 6];
153
154 let uuid = Uuid::now_v6(&node);
155
156 assert_eq!(uuid.get_version(), Some(Version::SortMac));
157 assert_eq!(uuid.get_variant(), Variant::RFC4122);
158 }
159}