Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More work on docs #631

Merged
merged 2 commits into from Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 31 additions & 5 deletions src/builder.rs
Expand Up @@ -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};
Expand All @@ -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<dyn std::error::Error>> {
/// # 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);
Expand Down Expand Up @@ -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))
}
Expand Down Expand Up @@ -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,
Expand Down
65 changes: 51 additions & 14 deletions src/lib.rs
Expand Up @@ -85,14 +85,18 @@
//! * `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?
//!
//! If you just want to generate unique identifiers then consider version 4 (`v4`) UUIDs. If you want
//! 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:
Expand Down Expand Up @@ -132,9 +136,10 @@
//!
//! ```toml
//! [dependencies.uuid]
//! version = "1"
//! version = "1.1.2"
//! features = [
//! "v4",
//! "v7",
//! "js",
//! ]
//! ```
Expand All @@ -146,7 +151,7 @@
//!
//! ```toml
//! [dependencies.uuid]
//! version = "1"
//! version = "1.1.2"
//! default-features = false
//! ```
//!
Expand All @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -302,6 +308,8 @@ pub enum Version {
SortRand,
/// Version 8: Custom.
Custom,
/// The "max" (all ones) UUID.
Max = 0xff,
}

/// The reserved variants of UUIDs.
Expand All @@ -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.
Expand Down Expand Up @@ -545,6 +554,7 @@ impl Uuid {
6 => Some(Version::SortMac),
7 => Some(Version::SortRand),
8 => Some(Version::Custom),
0xf => Some(Version::Max),
_ => None,
}
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down
24 changes: 21 additions & 3 deletions src/v1.rs
Expand Up @@ -8,26 +8,32 @@ 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());

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
Expand Down Expand Up @@ -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() {
Expand Down
34 changes: 26 additions & 8 deletions src/v6.rs
Expand Up @@ -6,29 +6,35 @@
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());

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
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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];
Expand Down
9 changes: 4 additions & 5 deletions src/v7.rs
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand All @@ -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));
Expand All @@ -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;

Expand Down