mirror of
https://github.com/uuid-rs/uuid.git
synced 2025-09-30 06:21:02 +00:00
shift some more code around
This commit is contained in:
parent
c31ddafb29
commit
c60dd9404a
@ -7,7 +7,7 @@
|
||||
fn generate_sortable_uuid() {
|
||||
use uuid::Uuid;
|
||||
|
||||
let uuid = Uuid::new_v7(uuid::Timestamp::now(uuid::NoContext));
|
||||
let uuid = Uuid::now_v7();
|
||||
|
||||
assert_eq!(Some(uuid::Version::SortRand), uuid.get_version());
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
//!
|
||||
//! [`Uuid`]: ../struct.Uuid.html
|
||||
|
||||
use crate::{error::*, Bytes, Uuid, Variant, Version};
|
||||
use crate::{error::*, timestamp, Bytes, Uuid, Variant, Version};
|
||||
|
||||
/// A builder struct for creating a UUID.
|
||||
///
|
||||
@ -43,12 +43,14 @@ use crate::{error::*, Bytes, Uuid, Variant, Version};
|
||||
pub struct Builder(Uuid);
|
||||
|
||||
impl Uuid {
|
||||
/// The 'nil UUID'.
|
||||
/// The 'nil UUID' (all zeros).
|
||||
///
|
||||
/// The nil UUID is a special form of UUID that is specified to have all
|
||||
/// 128 bits set to zero, as defined in [IETF RFC 4122 Section 4.1.7][RFC].
|
||||
/// 128 bits set to zero.
|
||||
///
|
||||
/// [RFC]: https://tools.ietf.org/html/rfc4122.html#section-4.1.7
|
||||
/// # References
|
||||
///
|
||||
/// * [Nil UUID in RFC4122]: https://tools.ietf.org/html/rfc4122.html#section-4.1.7
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -67,12 +69,14 @@ impl Uuid {
|
||||
Uuid::from_bytes([0; 16])
|
||||
}
|
||||
|
||||
/// The 'max UUID'.
|
||||
/// The 'max UUID' (all ones).
|
||||
///
|
||||
/// The max UUID is a special form of UUID that is specified to have all
|
||||
/// 128 bits set to one, as defined in [IETF RFC 4122 Update Section 5.4][Draft RFC].
|
||||
/// 128 bits set to one.
|
||||
///
|
||||
/// [Draft RFC]: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#page-12
|
||||
/// # References
|
||||
///
|
||||
/// * [Max UUID in Draft RFC: New UUID Formats, Version 4]: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -141,6 +145,8 @@ impl Uuid {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # use uuid::Uuid;
|
||||
/// let d1 = 0xa1a2a3a4;
|
||||
@ -539,7 +545,7 @@ impl Builder {
|
||||
|
||||
/// Creates a `Builder` for a version 1 UUID using the supplied timestamp and node id.
|
||||
pub const fn from_rfc4122_timestamp(ticks: u64, counter: u16, node_id: &[u8; 6]) -> Self {
|
||||
Builder(crate::v1::encode_rfc4122_timestamp(ticks, counter, node_id))
|
||||
Builder(timestamp::encode_rfc4122_timestamp(ticks, counter, node_id))
|
||||
}
|
||||
|
||||
/// Creates a `Builder` for a version 3 UUID using the supplied MD5 hashed bytes.
|
||||
@ -574,9 +580,9 @@ impl Builder {
|
||||
.with_version(Version::Random)
|
||||
}
|
||||
|
||||
/// Creates a `Builder` for a version 5 UUID using the supplied SHA1 hashed bytes.
|
||||
/// Creates a `Builder` for a version 5 UUID using the supplied SHA-1 hashed bytes.
|
||||
///
|
||||
/// This method assumes the bytes are already a SHA1 hash, it will only set the appropriate
|
||||
/// This method assumes the bytes are already a SHA-1 hash, it will only set the appropriate
|
||||
/// bits for the UUID version and variant.
|
||||
pub const fn from_sha1_bytes(sha1_bytes: Bytes) -> Self {
|
||||
Builder(Uuid::from_bytes(sha1_bytes))
|
||||
@ -592,22 +598,21 @@ impl Builder {
|
||||
counter: u16,
|
||||
node_id: &[u8; 6],
|
||||
) -> Self {
|
||||
Builder(crate::v6::encode_sorted_rfc4122_timestamp(
|
||||
Builder(timestamp::encode_sorted_rfc4122_timestamp(
|
||||
ticks, counter, node_id,
|
||||
))
|
||||
}
|
||||
|
||||
/// Creates a `Builder` for a version 7 UUID using the supplied Unix timestamp.
|
||||
/// Creates a `Builder` for a version 7 UUID using the supplied Unix timestamp and random bytes.
|
||||
///
|
||||
/// This method will encode the duration since the Unix epoch at millisecond precision, filling
|
||||
/// the rest with data from the given random bytes. This method assumes the bytes are already
|
||||
/// sufficiently random.
|
||||
/// This method assumes the bytes are already sufficiently random.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Creating a UUID using the current system timestamp:
|
||||
///
|
||||
/// ```
|
||||
/// # use std::convert::TryInto;
|
||||
/// use std::time::{Duration, SystemTime};
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// # use uuid::{Builder, Uuid, Variant, Version, Timestamp, NoContext};
|
||||
@ -618,7 +623,7 @@ impl Builder {
|
||||
///
|
||||
/// let random_bytes = rng();
|
||||
///
|
||||
/// let uuid = Builder::from_unix_timestamp(ts.as_secs(), ts.subsec_millis(), &random_bytes).into_uuid();
|
||||
/// let uuid = Builder::from_unix_timestamp(ts.as_millis().try_into()?, &random_bytes).into_uuid();
|
||||
///
|
||||
/// assert_eq!(Some(Version::SortRand), uuid.get_version());
|
||||
/// assert_eq!(Variant::RFC4122, uuid.get_variant());
|
||||
@ -626,7 +631,7 @@ impl Builder {
|
||||
/// # }
|
||||
/// ```
|
||||
pub const fn from_unix_timestamp_millis(millis: u64, random_bytes: &[u8; 10]) -> Self {
|
||||
Builder(crate::v7::encode_unix_timestamp_millis(
|
||||
Builder(timestamp::encode_unix_timestamp_millis(
|
||||
millis,
|
||||
random_bytes,
|
||||
))
|
||||
|
11
src/lib.rs
11
src/lib.rs
@ -31,7 +31,7 @@
|
||||
//! be extremely unlikely.
|
||||
//!
|
||||
//! UUIDs have a number of standardized encodings that are specified in [RFC4122](http://tools.ietf.org/html/rfc4122),
|
||||
//! with recent additions [in draft](https://github.com/uuid6/uuid6-ietf-draft).
|
||||
//! with recent additions [in draft](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04).
|
||||
//!
|
||||
//! # Getting started
|
||||
//!
|
||||
@ -193,7 +193,7 @@
|
||||
//!
|
||||
//! * [Wikipedia: Universally Unique Identifier](http://en.wikipedia.org/wiki/Universally_unique_identifier)
|
||||
//! * [RFC4122: A Universally Unique Identifier (UUID) URN Namespace](http://tools.ietf.org/html/rfc4122)
|
||||
//! * [Draft RFC: New UUID Formats](https://github.com/uuid6/uuid6-ietf-draft)
|
||||
//! * [Draft RFC: New UUID Formats, Version 4](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04)
|
||||
//!
|
||||
//! [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen
|
||||
//! [`cargo-web`]: https://crates.io/crates/cargo-web
|
||||
@ -264,6 +264,7 @@ mod external;
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
extern crate alloc;
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "macro-diagnostics")]
|
||||
pub extern crate private_uuid_macro_internal;
|
||||
@ -894,17 +895,17 @@ impl Uuid {
|
||||
pub const fn get_timestamp(&self) -> Option<Timestamp> {
|
||||
match self.get_version() {
|
||||
Some(Version::Mac) => {
|
||||
let (ticks, counter) = v1::decode_rfc4122_timestamp(self);
|
||||
let (ticks, counter) = timestamp::decode_rfc4122_timestamp(self);
|
||||
|
||||
Some(Timestamp::from_rfc4122(ticks, counter))
|
||||
}
|
||||
Some(Version::SortMac) => {
|
||||
let (ticks, counter) = v6::decode_sorted_rfc4122_timestamp(self);
|
||||
let (ticks, counter) = timestamp::decode_sorted_rfc4122_timestamp(self);
|
||||
|
||||
Some(Timestamp::from_rfc4122(ticks, counter))
|
||||
}
|
||||
Some(Version::SortRand) => {
|
||||
let millis = v7::decode_unix_timestamp_millis(self);
|
||||
let millis = timestamp::decode_unix_timestamp_millis(self);
|
||||
|
||||
let seconds = millis / 1000;
|
||||
let nanos = ((millis % 1000) * 1_000_000) as u32;
|
||||
|
@ -18,7 +18,7 @@ pub(crate) fn bytes() -> [u8; 16] {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1", feature = "v6", feature = "v7"))]
|
||||
#[cfg(any(feature = "v1", feature = "v6"))]
|
||||
pub(crate) fn u16() -> u16 {
|
||||
#[cfg(not(feature = "fast-rng"))]
|
||||
{
|
||||
|
114
src/timestamp.rs
114
src/timestamp.rs
@ -18,6 +18,9 @@
|
||||
//! # References
|
||||
//!
|
||||
//! * [Timestamp in RFC4122](https://www.rfc-editor.org/rfc/rfc4122#section-4.1.4)
|
||||
//! * [Timestamp in Draft RFC: New UUID Formats, Version 4](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-6.1)
|
||||
|
||||
use crate::Uuid;
|
||||
|
||||
/// The number of 100 nanosecond ticks between the RFC4122 epoch
|
||||
/// (`1582-10-15 00:00:00`) and the Unix epoch (`1970-01-01 00:00:00`).
|
||||
@ -32,6 +35,7 @@ pub const UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;
|
||||
/// # References
|
||||
///
|
||||
/// * [Timestamp in RFC4122](https://www.rfc-editor.org/rfc/rfc4122#section-4.1.4)
|
||||
/// * [Timestamp in Draft RFC: New UUID Formats, Version 4](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-6.1)
|
||||
/// * [Clock Sequence in RFC4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.5)
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Timestamp {
|
||||
@ -152,6 +156,116 @@ impl Timestamp {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn encode_rfc4122_timestamp(ticks: u64, counter: u16, node_id: &[u8; 6]) -> Uuid {
|
||||
let time_low = (ticks & 0xFFFF_FFFF) as u32;
|
||||
let time_mid = ((ticks >> 32) & 0xFFFF) as u16;
|
||||
let time_high_and_version = (((ticks >> 48) & 0x0FFF) as u16) | (1 << 12);
|
||||
|
||||
let mut d4 = [0; 8];
|
||||
|
||||
d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
|
||||
d4[1] = (counter & 0xFF) as u8;
|
||||
d4[2] = node_id[0];
|
||||
d4[3] = node_id[1];
|
||||
d4[4] = node_id[2];
|
||||
d4[5] = node_id[3];
|
||||
d4[6] = node_id[4];
|
||||
d4[7] = node_id[5];
|
||||
|
||||
Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
|
||||
}
|
||||
|
||||
pub(crate) const fn decode_rfc4122_timestamp(uuid: &Uuid) -> (u64, u16) {
|
||||
let bytes = uuid.as_bytes();
|
||||
|
||||
let ticks: u64 = ((bytes[6] & 0x0F) as u64) << 56
|
||||
| (bytes[7] as u64) << 48
|
||||
| (bytes[4] as u64) << 40
|
||||
| (bytes[5] as u64) << 32
|
||||
| (bytes[0] as u64) << 24
|
||||
| (bytes[1] as u64) << 16
|
||||
| (bytes[2] as u64) << 8
|
||||
| (bytes[3] as u64);
|
||||
|
||||
let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
|
||||
|
||||
(ticks, counter)
|
||||
}
|
||||
|
||||
pub(crate) const fn encode_sorted_rfc4122_timestamp(
|
||||
ticks: u64,
|
||||
counter: u16,
|
||||
node_id: &[u8; 6],
|
||||
) -> Uuid {
|
||||
let time_high = ((ticks >> 28) & 0xFFFF_FFFF) as u32;
|
||||
let time_mid = ((ticks >> 12) & 0xFFFF) as u16;
|
||||
let time_low_and_version = ((ticks & 0x0FFF) as u16) | (0x6 << 12);
|
||||
|
||||
let mut d4 = [0; 8];
|
||||
|
||||
d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
|
||||
d4[1] = (counter & 0xFF) as u8;
|
||||
d4[2] = node_id[0];
|
||||
d4[3] = node_id[1];
|
||||
d4[4] = node_id[2];
|
||||
d4[5] = node_id[3];
|
||||
d4[6] = node_id[4];
|
||||
d4[7] = node_id[5];
|
||||
|
||||
Uuid::from_fields(time_high, time_mid, time_low_and_version, &d4)
|
||||
}
|
||||
|
||||
pub(crate) const fn decode_sorted_rfc4122_timestamp(uuid: &Uuid) -> (u64, u16) {
|
||||
let bytes = uuid.as_bytes();
|
||||
|
||||
let ticks: u64 = ((bytes[0]) as u64) << 52
|
||||
| (bytes[1] as u64) << 44
|
||||
| (bytes[2] as u64) << 36
|
||||
| (bytes[3] as u64) << 28
|
||||
| (bytes[4] as u64) << 20
|
||||
| (bytes[5] as u64) << 12
|
||||
| ((bytes[6] & 0xF) as u64) << 8
|
||||
| (bytes[7] as u64);
|
||||
|
||||
let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
|
||||
|
||||
(ticks, counter)
|
||||
}
|
||||
|
||||
pub(crate) const fn encode_unix_timestamp_millis(millis: u64, random_bytes: &[u8; 10]) -> Uuid {
|
||||
let millis_high = ((millis >> 16) & 0xFFFF_FFFF) as u32;
|
||||
let millis_low = (millis & 0xFFFF) as u16;
|
||||
|
||||
let random_and_version =
|
||||
(random_bytes[0] as u16 | ((random_bytes[1] as u16) << 8) & 0x0FFF) | (0x7 << 12);
|
||||
|
||||
let mut d4 = [0; 8];
|
||||
|
||||
d4[0] = (random_bytes[2] & 0x3F) | 0x80;
|
||||
d4[1] = random_bytes[3];
|
||||
d4[2] = random_bytes[4];
|
||||
d4[3] = random_bytes[5];
|
||||
d4[4] = random_bytes[6];
|
||||
d4[5] = random_bytes[7];
|
||||
d4[6] = random_bytes[8];
|
||||
d4[7] = random_bytes[9];
|
||||
|
||||
Uuid::from_fields(millis_high, millis_low, random_and_version, &d4)
|
||||
}
|
||||
|
||||
pub(crate) const fn decode_unix_timestamp_millis(uuid: &Uuid) -> u64 {
|
||||
let bytes = uuid.as_bytes();
|
||||
|
||||
let millis: u64 = (bytes[0] as u64) << 40
|
||||
| (bytes[1] as u64) << 32
|
||||
| (bytes[2] as u64) << 24
|
||||
| (bytes[3] as u64) << 16
|
||||
| (bytes[4] as u64) << 8
|
||||
| (bytes[5] as u64);
|
||||
|
||||
millis
|
||||
}
|
||||
|
||||
/// A counter that can be used by version 1 and version 6 UUIDs to support
|
||||
/// the uniqueness of timestamps.
|
||||
///
|
||||
|
54
src/v1.rs
54
src/v1.rs
@ -8,9 +8,12 @@ use crate::{timestamp::context::shared_context, Builder, Timestamp, Uuid};
|
||||
pub use crate::timestamp::context::Context;
|
||||
|
||||
impl Uuid {
|
||||
/// Create a new UUID (version 1) using the current system time and a node id.
|
||||
/// Create a new version 1 UUID using the current system time and a node id.
|
||||
///
|
||||
/// This method is only available if both the `std` and `rng` features are enabled.
|
||||
///
|
||||
/// This method is a convenient alternative to [`Uuid::new_v1`] that uses the current system time
|
||||
/// as the source timestamp.
|
||||
#[cfg(all(feature = "std", feature = "rng"))]
|
||||
pub fn now_v1(node_id: &[u8; 6]) -> Self {
|
||||
let ts = Timestamp::now(shared_context());
|
||||
@ -18,7 +21,7 @@ impl Uuid {
|
||||
Self::new_v1(ts, node_id)
|
||||
}
|
||||
|
||||
/// Create a new UUID (version 1) using the given timestamp and node id.
|
||||
/// Create a new version 1 UUID using the given timestamp and node id.
|
||||
///
|
||||
/// When generating [`Timestamp`]s using a [`ClockSequence`], this function
|
||||
/// is only guaranteed to produce unique values if the following conditions
|
||||
@ -71,17 +74,6 @@ impl Uuid {
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// The timestamp can also just use the current SystemTime
|
||||
///
|
||||
/// ```
|
||||
/// # use uuid::{Timestamp, Context};
|
||||
/// # use uuid::Uuid;
|
||||
/// let context = Context::new(42);
|
||||
/// let ts = Timestamp::now(&context);
|
||||
///
|
||||
/// let _uuid = Uuid::new_v1(ts, &[1, 2, 3, 4, 5, 6]);
|
||||
/// ```
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// * [Version 1 UUIDs in RFC4122](https://www.rfc-editor.org/rfc/rfc4122#section-4.2)
|
||||
@ -96,42 +88,6 @@ impl Uuid {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn encode_rfc4122_timestamp(ticks: u64, counter: u16, node_id: &[u8; 6]) -> Uuid {
|
||||
let time_low = (ticks & 0xFFFF_FFFF) as u32;
|
||||
let time_mid = ((ticks >> 32) & 0xFFFF) as u16;
|
||||
let time_high_and_version = (((ticks >> 48) & 0x0FFF) as u16) | (1 << 12);
|
||||
|
||||
let mut d4 = [0; 8];
|
||||
|
||||
d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
|
||||
d4[1] = (counter & 0xFF) as u8;
|
||||
d4[2] = node_id[0];
|
||||
d4[3] = node_id[1];
|
||||
d4[4] = node_id[2];
|
||||
d4[5] = node_id[3];
|
||||
d4[6] = node_id[4];
|
||||
d4[7] = node_id[5];
|
||||
|
||||
Uuid::from_fields(time_low, time_mid, time_high_and_version, &d4)
|
||||
}
|
||||
|
||||
pub(crate) const fn decode_rfc4122_timestamp(uuid: &Uuid) -> (u64, u16) {
|
||||
let bytes = uuid.as_bytes();
|
||||
|
||||
let ticks: u64 = ((bytes[6] & 0x0F) as u64) << 56
|
||||
| (bytes[7] as u64) << 48
|
||||
| (bytes[4] as u64) << 40
|
||||
| (bytes[5] as u64) << 32
|
||||
| (bytes[0] as u64) << 24
|
||||
| (bytes[1] as u64) << 16
|
||||
| (bytes[2] as u64) << 8
|
||||
| (bytes[3] as u64);
|
||||
|
||||
let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
|
||||
|
||||
(ticks, counter)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
49
src/v6.rs
49
src/v6.rs
@ -6,9 +6,12 @@
|
||||
use crate::{timestamp::context::shared_context, Builder, Timestamp, Uuid};
|
||||
|
||||
impl Uuid {
|
||||
/// Create a new UUID (version 6) using the current time value and a node id.
|
||||
/// Create a new version 6 UUID using the current time value and a node id.
|
||||
///
|
||||
/// This method is only available if the `std` feature is enabled.
|
||||
///
|
||||
/// This method is a convenient alternative to [`Uuid::new_v6`] that uses the current system time
|
||||
/// as the source timestamp.
|
||||
#[cfg(all(feature = "std", feature = "rng"))]
|
||||
pub fn now_v6(node_id: &[u8; 6]) -> Self {
|
||||
let ts = Timestamp::now(shared_context());
|
||||
@ -16,9 +19,9 @@ impl Uuid {
|
||||
Self::new_v6(ts, node_id)
|
||||
}
|
||||
|
||||
/// Create a new UUID (version 6) using a time value + sequence +
|
||||
/// Create a new version 6 UUID using a time value + sequence +
|
||||
/// *NodeId*.
|
||||
/// This is similar to UUIDv1, except that it is lexographically sortable by timestamp.
|
||||
/// This is similar to UUIDv1, except that it is lexicographically sortable by timestamp.
|
||||
///
|
||||
/// When generating [`Timestamp`]s using a [`ClockSequence`], this function
|
||||
/// is only guaranteed to produce unique values if the following conditions
|
||||
@ -87,46 +90,6 @@ impl Uuid {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn encode_sorted_rfc4122_timestamp(
|
||||
ticks: u64,
|
||||
counter: u16,
|
||||
node_id: &[u8; 6],
|
||||
) -> Uuid {
|
||||
let time_high = ((ticks >> 28) & 0xFFFF_FFFF) as u32;
|
||||
let time_mid = ((ticks >> 12) & 0xFFFF) as u16;
|
||||
let time_low_and_version = ((ticks & 0x0FFF) as u16) | (0x6 << 12);
|
||||
|
||||
let mut d4 = [0; 8];
|
||||
|
||||
d4[0] = (((counter & 0x3F00) >> 8) as u8) | 0x80;
|
||||
d4[1] = (counter & 0xFF) as u8;
|
||||
d4[2] = node_id[0];
|
||||
d4[3] = node_id[1];
|
||||
d4[4] = node_id[2];
|
||||
d4[5] = node_id[3];
|
||||
d4[6] = node_id[4];
|
||||
d4[7] = node_id[5];
|
||||
|
||||
Uuid::from_fields(time_high, time_mid, time_low_and_version, &d4)
|
||||
}
|
||||
|
||||
pub(crate) const fn decode_sorted_rfc4122_timestamp(uuid: &Uuid) -> (u64, u16) {
|
||||
let bytes = uuid.as_bytes();
|
||||
|
||||
let ticks: u64 = ((bytes[0]) as u64) << 52
|
||||
| (bytes[1] as u64) << 44
|
||||
| (bytes[2] as u64) << 36
|
||||
| (bytes[3] as u64) << 28
|
||||
| (bytes[4] as u64) << 20
|
||||
| (bytes[5] as u64) << 12
|
||||
| ((bytes[6] & 0xF) as u64) << 8
|
||||
| (bytes[7] as u64);
|
||||
|
||||
let counter: u16 = ((bytes[8] & 0x3F) as u16) << 8 | (bytes[9] as u16);
|
||||
|
||||
(ticks, counter)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
58
src/v7.rs
58
src/v7.rs
@ -7,7 +7,7 @@ use crate::{rng, timestamp::Timestamp, Builder, NoContext, Uuid};
|
||||
use core::convert::TryInto;
|
||||
|
||||
impl Uuid {
|
||||
/// Create a new UUID (version 7) using the current time value and random bytes.
|
||||
/// Create a new version 7 UUID using the current time value and random bytes.
|
||||
///
|
||||
/// This method is a convenient alternative to [`Uuid::new_v7`] that uses the current system time
|
||||
/// as the source timestamp.
|
||||
@ -16,13 +16,16 @@ impl Uuid {
|
||||
Self::new_v7(Timestamp::now(NoContext))
|
||||
}
|
||||
|
||||
/// Create a new UUID (version 7) using a time value and random bytes.
|
||||
/// Create a new version 7 UUID using a time value and random bytes.
|
||||
///
|
||||
/// When the `std` feature is enabled, you can also use [`Uuid::now_v7`].
|
||||
///
|
||||
/// Note that usage of this method requires the `v7` feature of this crate
|
||||
/// to be enabled.
|
||||
///
|
||||
/// Also see [`Uuid::now_v7`] for a convenient way to generate version 7
|
||||
/// UUIDs using the current system time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// A v7 UUID can be created from a unix [`Timestamp`] plus a 128 bit
|
||||
@ -44,67 +47,34 @@ impl Uuid {
|
||||
/// * [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)
|
||||
pub fn new_v7(ts: Timestamp) -> Self {
|
||||
let (secs, nanos) = ts.to_unix();
|
||||
let millis = secs.saturating_add(nanos as u64 / 1_000_000);
|
||||
let millis = (secs * 1000).saturating_add(nanos as u64 / 1_000_000);
|
||||
|
||||
Builder::from_unix_timestamp_millis(millis, &rng::bytes()[..10].try_into().unwrap())
|
||||
.into_uuid()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn encode_unix_timestamp_millis(millis: u64, random_bytes: &[u8; 10]) -> Uuid {
|
||||
let millis_high = ((millis >> 16) & 0xFFFF_FFFF) as u32;
|
||||
let millis_low = (millis & 0xFFFF) as u16;
|
||||
|
||||
let random_and_version =
|
||||
(random_bytes[0] as u16 | ((random_bytes[1] as u16) << 8) & 0x0FFF) | (0x7 << 12);
|
||||
|
||||
let mut d4 = [0; 8];
|
||||
|
||||
d4[0] = (random_bytes[2] & 0x3F) | 0x80;
|
||||
d4[1] = random_bytes[3];
|
||||
d4[2] = random_bytes[4];
|
||||
d4[3] = random_bytes[5];
|
||||
d4[4] = random_bytes[6];
|
||||
d4[5] = random_bytes[7];
|
||||
d4[6] = random_bytes[8];
|
||||
d4[7] = random_bytes[9];
|
||||
|
||||
Uuid::from_fields(millis_high, millis_low, random_and_version, &d4)
|
||||
}
|
||||
|
||||
pub(crate) const fn decode_unix_timestamp_millis(uuid: &Uuid) -> u64 {
|
||||
let bytes = uuid.as_bytes();
|
||||
|
||||
let millis: u64 = (bytes[0] as u64) << 40
|
||||
| (bytes[1] as u64) << 32
|
||||
| (bytes[2] as u64) << 24
|
||||
| (bytes[3] as u64) << 16
|
||||
| (bytes[4] as u64) << 8
|
||||
| (bytes[5] as u64);
|
||||
|
||||
millis
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{NoContext, Variant, Version};
|
||||
use std::string::ToString;
|
||||
use crate::{std::string::ToString, NoContext, Variant, Version};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn test_new_v7() {
|
||||
let time: u64 = 1_496_854_535;
|
||||
let time_fraction: u32 = 812_946_000;
|
||||
let ts: u64 = 1645557742000;
|
||||
|
||||
let uuid = Uuid::new_v7(Timestamp::from_unix(NoContext, time, time_fraction));
|
||||
let seconds = ts / 1000;
|
||||
let nanos = ((ts % 1000) * 1_000_000) as u32;
|
||||
|
||||
let uuid = Uuid::new_v7(Timestamp::from_unix(NoContext, seconds, nanos));
|
||||
let uustr = uuid.hyphenated().to_string();
|
||||
|
||||
assert_eq!(uuid.get_version(), Some(Version::SortRand));
|
||||
assert_eq!(uuid.get_variant(), Variant::RFC4122);
|
||||
assert!(uustr.starts_with("015c837b-9e84-7"));
|
||||
assert!(uuid.hyphenated().to_string().starts_with("017f22e2-79b0-7"));
|
||||
|
||||
// Ensure parsing the same UUID produces the same timestamp
|
||||
let parsed = Uuid::parse_str(uustr.as_str()).unwrap();
|
||||
@ -116,7 +86,7 @@ mod tests {
|
||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
|
||||
fn test_new_v7_timestamp_roundtrip() {
|
||||
let time: u64 = 1_496_854_535;
|
||||
let time_fraction: u32 = 812_946_000;
|
||||
let time_fraction: u32 = 812_000_000;
|
||||
|
||||
let ts = Timestamp::from_unix(NoContext, time, time_fraction);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user