1 //! The implementation for Version 7 UUIDs. 2 //! 3 //! Note that you need to enable the `v7` Cargo feature 4 //! in order to use this module. 5 6 use crate::{rng, std::convert::TryInto, timestamp::Timestamp, Builder, Uuid}; 7 8 impl Uuid { 9 /// Create a new version 7 UUID using the current time value and random bytes. 10 /// 11 /// This method is a convenient alternative to [`Uuid::new_v7`] that uses the current system time 12 /// as the source timestamp. 13 #[cfg(feature = "std")] now_v7() -> Self14 pub fn now_v7() -> Self { 15 Self::new_v7(Timestamp::now(crate::NoContext)) 16 } 17 18 /// Create a new version 7 UUID using a time value and random bytes. 19 /// 20 /// When the `std` feature is enabled, you can also use [`Uuid::now_v7`]. 21 /// 22 /// Note that usage of this method requires the `v7` feature of this crate 23 /// to be enabled. 24 /// 25 /// Also see [`Uuid::now_v7`] for a convenient way to generate version 7 26 /// UUIDs using the current system time. 27 /// 28 /// # Examples 29 /// 30 /// A v7 UUID can be created from a unix [`Timestamp`] plus a 128 bit 31 /// random number. When supplied as such, the data will be 32 /// 33 /// ```rust 34 /// # use uuid::{Uuid, Timestamp, NoContext}; 35 /// let ts = Timestamp::from_unix(NoContext, 1497624119, 1234); 36 /// 37 /// let uuid = Uuid::new_v7(ts); 38 /// 39 /// assert!( 40 /// uuid.hyphenated().to_string().starts_with("015cb15a-86d8-7") 41 /// ); 42 /// ``` 43 /// 44 /// # References 45 /// 46 /// * [Version 7 UUIDs in Draft RFC: New UUID Formats, Version 4](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2) new_v7(ts: Timestamp) -> Self47 pub fn new_v7(ts: Timestamp) -> Self { 48 let (secs, nanos) = ts.to_unix(); 49 let millis = (secs * 1000).saturating_add(nanos as u64 / 1_000_000); 50 51 Builder::from_unix_timestamp_millis(millis, &rng::bytes()[..10].try_into().unwrap()) 52 .into_uuid() 53 } 54 } 55 56 #[cfg(test)] 57 mod tests { 58 use super::*; 59 use crate::{std::string::ToString, NoContext, Variant, Version}; 60 #[cfg(all( 61 target_arch = "wasm32", 62 target_vendor = "unknown", 63 target_os = "unknown" 64 ))] 65 use wasm_bindgen_test::*; 66 67 #[test] 68 #[cfg_attr( 69 all( 70 target_arch = "wasm32", 71 target_vendor = "unknown", 72 target_os = "unknown" 73 ), 74 wasm_bindgen_test 75 )] test_new()76 fn test_new() { 77 let ts: u64 = 1645557742000; 78 79 let seconds = ts / 1000; 80 let nanos = ((ts % 1000) * 1_000_000) as u32; 81 82 let uuid = Uuid::new_v7(Timestamp::from_unix(NoContext, seconds, nanos)); 83 let uustr = uuid.hyphenated().to_string(); 84 85 assert_eq!(uuid.get_version(), Some(Version::SortRand)); 86 assert_eq!(uuid.get_variant(), Variant::RFC4122); 87 assert!(uuid.hyphenated().to_string().starts_with("017f22e2-79b0-7")); 88 89 // Ensure parsing the same UUID produces the same timestamp 90 let parsed = Uuid::parse_str(uustr.as_str()).unwrap(); 91 92 assert_eq!(uuid, parsed); 93 } 94 95 #[test] 96 #[cfg_attr( 97 all( 98 target_arch = "wasm32", 99 target_vendor = "unknown", 100 target_os = "unknown" 101 ), 102 wasm_bindgen_test 103 )] 104 #[cfg(feature = "std")] test_now()105 fn test_now() { 106 let uuid = Uuid::now_v7(); 107 108 assert_eq!(uuid.get_version(), Some(Version::SortRand)); 109 assert_eq!(uuid.get_variant(), Variant::RFC4122); 110 } 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_sorting()121 fn test_sorting() { 122 let time1: u64 = 1_496_854_535; 123 let time_fraction1: u32 = 812_000_000; 124 125 let time2 = time1 + 4000; 126 let time_fraction2 = time_fraction1; 127 128 let uuid1 = Uuid::new_v7(Timestamp::from_unix(NoContext, time1, time_fraction1)); 129 let uuid2 = Uuid::new_v7(Timestamp::from_unix(NoContext, time2, time_fraction2)); 130 131 assert!(uuid1.as_bytes() < uuid2.as_bytes()); 132 assert!(uuid1.to_string() < uuid2.to_string()); 133 } 134 135 #[test] 136 #[cfg_attr( 137 all( 138 target_arch = "wasm32", 139 target_vendor = "unknown", 140 target_os = "unknown" 141 ), 142 wasm_bindgen_test 143 )] test_new_timestamp_roundtrip()144 fn test_new_timestamp_roundtrip() { 145 let time: u64 = 1_496_854_535; 146 let time_fraction: u32 = 812_000_000; 147 148 let ts = Timestamp::from_unix(NoContext, time, time_fraction); 149 150 let uuid = Uuid::new_v7(ts); 151 152 let decoded_ts = uuid.get_timestamp().unwrap(); 153 154 assert_eq!(ts.to_unix(), decoded_ts.to_unix()); 155 } 156 } 157