diff --git a/src/builder.rs b/src/builder.rs index 315512fa..bf3b3611 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -15,15 +15,19 @@ use crate::{error::*, timestamp, Bytes, Uuid, Variant, Version}; -/// A builder struct for creating a UUID. +/// A builder for creating a UUID. /// /// This type is useful if you need to mutate individual fields of a [`Uuid`] /// while constructing it. Since the [`Uuid`] type is `Copy`, it doesn't offer /// any methods to mutate in place. They live on the `Builder` instead. /// +/// The `Builder` type also always exposes APIs to construct [`Uuid`]s for any +/// version without needing crate features or additional dependencies. It's a +/// lower-level API than the methods on [`Uuid`]. +/// /// # Examples /// -/// Creating a v4 UUID from externally generated bytes: +/// Creating a version 4 UUID from externally generated random bytes: /// /// ``` /// # use uuid::{Builder, Version, Variant}; @@ -38,6 +42,28 @@ use crate::{error::*, timestamp, Bytes, Uuid, Variant, Version}; /// assert_eq!(Some(Version::Random), uuid.get_version()); /// assert_eq!(Variant::RFC4122, uuid.get_variant()); /// ``` +/// +/// Creating a version 7 UUID from the current system time and externally generated random bytes: +/// +/// ``` +/// # use std::convert::TryInto; +/// use std::time::{Duration, SystemTime}; +/// # fn main() -> Result<(), Box> { +/// # use uuid::{Builder, Uuid, Variant, Version, Timestamp, NoContext}; +/// # let rng = || [ +/// # 70, 235, 208, 238, 14, 109, 67, 201, 185, 13 +/// # ]; +/// let ts = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?; +/// +/// let random_bytes = rng(); +/// +/// let uuid = Builder::from_unix_timestamp_millis(ts.as_millis().try_into()?, &random_bytes).into_uuid(); +/// +/// assert_eq!(Some(Version::SortRand), uuid.get_version()); +/// assert_eq!(Variant::RFC4122, uuid.get_variant()); +/// # Ok(()) +/// # } +/// ``` #[allow(missing_copy_implementations)] #[derive(Debug)] pub struct Builder(Uuid); @@ -543,7 +569,7 @@ impl Builder { Builder(Uuid::from_bytes_le(b)) } - /// Creates a `Builder` for a version 1 UUID using the supplied timestamp and node id. + /// 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(timestamp::encode_rfc4122_timestamp(ticks, counter, node_id)) } @@ -590,9 +616,9 @@ impl Builder { .with_version(Version::Sha1) } - /// Creates a `Builder` for a version 6 UUID using the supplied timestamp and node id. + /// Creates a `Builder` for a version 6 UUID using the supplied timestamp and node ID. /// - /// This method will encode the ticks, counter, and node id in a sortable UUID. + /// This method will encode the ticks, counter, and node ID in a sortable UUID. pub const fn from_sorted_rfc4122_timestamp( ticks: u64, counter: u16, diff --git a/src/lib.rs b/src/lib.rs index 22398679..ba1c9f7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,9 @@ //! * `v8` - Version 8 UUIDs using user-defined data. //! //! This library also includes a [`Builder`] type that can be used to help construct UUIDs of any -//! version without any additional dependencies or features. +//! version without any additional dependencies or features. It's a lower-level API than [`Uuid`] +//! that can be used when you need control over implicit requirements on things like a source +//! of randomness. //! //! ## Which UUID version should I use? //! @@ -93,6 +95,8 @@ //! to use UUIDs as database keys or need to sort them then consider version 7 (`v7`) UUIDs. //! Other versions should generally be avoided unless there's an existing need for them. //! +//! Some UUID versions supersede others. Prefer version 6 over version 1 and version 5 over version 3. +//! //! # Other features //! //! Other crate features can also be useful beyond the version support: @@ -132,9 +136,10 @@ //! //! ```toml //! [dependencies.uuid] -//! version = "1" +//! version = "1.1.2" //! features = [ //! "v4", +//! "v7", //! "js", //! ] //! ``` @@ -146,7 +151,7 @@ //! //! ```toml //! [dependencies.uuid] -//! version = "1" +//! version = "1.1.2" //! default-features = false //! ``` //! @@ -163,7 +168,7 @@ //! //! # Examples //! -//! To parse a UUID given in the simple format and print it as a URN: +//! Parse a UUID given in the simple format and print it as a URN: //! //! ``` //! # use uuid::Uuid; @@ -175,7 +180,7 @@ //! # } //! ``` //! -//! To create a new random (V4) UUID and print it out in hexadecimal form: +//! Generate a random UUID and print it out in hexadecimal form: //! //! ``` //! // Note that this requires the `v4` feature to be enabled. @@ -283,9 +288,10 @@ pub type Bytes = [u8; 16]; /// * [Version in RFC4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.3) #[derive(Clone, Copy, Debug, PartialEq)] #[non_exhaustive] +#[repr(u8)] pub enum Version { - /// The _nil_ (all zeros) UUID. - Nil = 0, + /// The "nil" (all zeros) UUID. + Nil = 0u8, /// Version 1: Timestamp and node ID. Mac, /// Version 2: DCE Security. @@ -302,6 +308,8 @@ pub enum Version { SortRand, /// Version 8: Custom. Custom, + /// The "max" (all ones) UUID. + Max = 0xff, } /// The reserved variants of UUIDs. @@ -311,9 +319,10 @@ pub enum Version { /// * [Variant in RFC4122](http://tools.ietf.org/html/rfc4122#section-4.1.1) #[derive(Clone, Copy, Debug, PartialEq)] #[non_exhaustive] +#[repr(u8)] pub enum Variant { /// Reserved by the NCS for backward compatibility. - NCS = 0, + NCS = 0u8, /// As described in the RFC4122 Specification (default). RFC4122, /// Reserved by Microsoft for backward compatibility. @@ -545,6 +554,7 @@ impl Uuid { 6 => Some(Version::SortMac), 7 => Some(Version::SortRand), 8 => Some(Version::Custom), + 0xf => Some(Version::Max), _ => None, } } @@ -835,9 +845,14 @@ impl Uuid { ] } - /// Tests if the UUID is nil. + /// Tests if the UUID is nil (all zeros). pub const fn is_nil(&self) -> bool { - self.as_u128() == 0 + self.as_u128() == u128::MIN + } + + /// Tests if the UUID is max (all ones). + pub const fn is_max(&self) -> bool { + self.as_u128() == u128::MAX } /// A buffer that can be used for `encode_...` calls, that is @@ -1062,19 +1077,41 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_nil() { - let nil = Uuid::nil(); - let not_nil = new(); + fn test_non_conforming() { let from_bytes = Uuid::from_bytes([4, 54, 67, 12, 43, 2, 2, 76, 32, 50, 87, 5, 1, 33, 43, 87]); assert_eq!(from_bytes.get_version(), None); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_nil() { + let nil = Uuid::nil(); + let not_nil = new(); assert!(nil.is_nil()); assert!(!not_nil.is_nil()); assert_eq!(nil.get_version(), Some(Version::Nil)); - assert_eq!(not_nil.get_version(), Some(Version::Random)) + assert_eq!(not_nil.get_version(), Some(Version::Random)); + + assert_eq!(nil, Builder::from_bytes([0; 16]).with_version(Version::Nil).into_uuid()); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_max() { + let max = Uuid::max(); + let not_max = new(); + + assert!(max.is_max()); + assert!(!not_max.is_max()); + + assert_eq!(max.get_version(), Some(Version::Max)); + assert_eq!(not_max.get_version(), Some(Version::Random)); + + assert_eq!(max, Builder::from_bytes([0xff; 16]).with_version(Version::Max).into_uuid()); } #[test] diff --git a/src/v1.rs b/src/v1.rs index 3b05fd0c..f1d50fb2 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -8,12 +8,15 @@ use crate::{Builder, Timestamp, Uuid}; pub use crate::timestamp::context::Context; impl Uuid { - /// Create a new version 1 UUID using the current system time and a node id. + /// Create a new version 1 UUID using the current system time and 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. + /// + /// Note that usage of this method requires the `v1`, `std`, and `rng` features of this crate + /// to be enabled. #[cfg(all(feature = "std", feature = "rng"))] pub fn now_v1(node_id: &[u8; 6]) -> Self { let ts = Timestamp::now(crate::timestamp::context::shared_context()); @@ -21,13 +24,16 @@ impl Uuid { Self::new_v1(ts, node_id) } - /// Create a new version 1 UUID using the given timestamp and node id. + /// Create a new version 1 UUID using the given timestamp and node ID. + /// + /// Also see [`Uuid::now_v1`] for a convenient way to generate version 1 + /// UUIDs using the current system time. /// /// When generating [`Timestamp`]s using a [`ClockSequence`], this function /// is only guaranteed to produce unique values if the following conditions /// hold: /// - /// 1. The *node id* is unique for this process, + /// 1. The *node ID* is unique for this process, /// 2. The *context* is shared across all threads which are generating version 1 /// UUIDs, /// 3. The [`ClockSequence`] implementation reliably returns unique @@ -126,6 +132,18 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg(all(feature = "std", feature = "rng"))] + fn test_now() { + let node = [1, 2, 3, 4, 5, 6]; + + let uuid = Uuid::now_v1(&node); + + assert_eq!(uuid.get_version(), Some(Version::Mac)); + assert_eq!(uuid.get_variant(), Variant::RFC4122); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_new_context() { diff --git a/src/v6.rs b/src/v6.rs index 4689a925..07644fd4 100644 --- a/src/v6.rs +++ b/src/v6.rs @@ -6,12 +6,15 @@ use crate::{Builder, Timestamp, Uuid}; impl Uuid { - /// Create a new version 6 UUID using the current time value and a node id. + /// Create a new version 6 UUID using the current system time and 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. + /// + /// Note that usage of this method requires the `v6`, `std`, and `rng` features of this crate + /// to be enabled. #[cfg(all(feature = "std", feature = "rng"))] pub fn now_v6(node_id: &[u8; 6]) -> Self { let ts = Timestamp::now(crate::timestamp::context::shared_context()); @@ -19,16 +22,19 @@ impl Uuid { Self::new_v6(ts, node_id) } - /// Create a new version 6 UUID using a time value + sequence + - /// *NodeId*. - /// This is similar to UUIDv1, except that it is lexicographically sortable by timestamp. + /// Create a new version 6 UUID using the given timestamp and a node ID. + /// + /// This is similar to version 1 UUIDs, except that it is lexicographically sortable by timestamp. + /// + /// Also see [`Uuid::now_v6`] for a convenient way to generate version 6 + /// UUIDs using the current system time. /// /// When generating [`Timestamp`]s using a [`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 + /// 1. The *node ID* is unique for this process, + /// 2. The *context* is shared across all threads which are generating version 6 /// UUIDs, /// 3. The [`ClockSequence`] implementation reliably returns unique /// clock sequences (this crate provides [`Context`] for this @@ -101,7 +107,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_new_v6() { + fn test_new() { let time: u64 = 1_496_854_535; let time_fraction: u32 = 812_946_000; let node = [1, 2, 3, 4, 5, 6]; @@ -131,7 +137,19 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_new_v6_context() { + #[cfg(all(feature = "std", feature = "rng"))] + fn test_now() { + let node = [1, 2, 3, 4, 5, 6]; + + let uuid = Uuid::now_v6(&node); + + assert_eq!(uuid.get_version(), Some(Version::SortMac)); + assert_eq!(uuid.get_variant(), Variant::RFC4122); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn test_new_context() { let time: u64 = 1_496_854_535; let time_fraction: u32 = 812_946_000; let node = [1, 2, 3, 4, 5, 6]; diff --git a/src/v7.rs b/src/v7.rs index a5ad01a0..dc8f4744 100644 --- a/src/v7.rs +++ b/src/v7.rs @@ -3,8 +3,7 @@ //! Note that you need to enable the `v7` Cargo feature //! in order to use this module. -use crate::{rng, timestamp::Timestamp, Builder, Uuid}; -use core::convert::TryInto; +use crate::{std::convert::TryInto, rng, timestamp::Timestamp, Builder, Uuid}; impl Uuid { /// Create a new version 7 UUID using the current time value and random bytes. @@ -63,7 +62,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_new_v7() { + fn test_new() { let ts: u64 = 1645557742000; let seconds = ts / 1000; @@ -85,7 +84,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[cfg(feature = "std")] - fn test_now_v7() { + fn test_now() { let uuid = Uuid::now_v7(); assert_eq!(uuid.get_version(), Some(Version::SortRand)); @@ -94,7 +93,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - fn test_new_v7_timestamp_roundtrip() { + fn test_new_timestamp_roundtrip() { let time: u64 = 1_496_854_535; let time_fraction: u32 = 812_000_000; diff --git a/src/v8.rs b/src/v8.rs index d3c64bdb..a54a9798 100644 --- a/src/v8.rs +++ b/src/v8.rs @@ -1,12 +1,15 @@ use crate::{Builder, Uuid}; impl Uuid { - /// Creates a custom UUID comprised almost entirely of user-supplied bytes + /// Creates a custom UUID comprised almost entirely of user-supplied bytes. /// /// This will inject the UUID Version at 4 bits starting at the 48th bit - /// and the Variant into 2 bits 64th bit. - /// So if there are bits are supplied in the input buffer, they will not be - /// visible in the result + /// and the Variant into 2 bits 64th bit. Any existing bits in the user-supplied bytes + /// at those locations will be overridden. + /// + /// Note that usage of this method requires the `v8` feature of this crate + /// to be enabled. + /// /// # Examples /// /// Basic usage: