From 8bbad764c3350d614754420054f7b236c88c8eb8 Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Thu, 26 Jun 2025 17:46:09 -0700 Subject: [PATCH] Update docs, tests, and improve conversion to UUIDs. --- Cargo.toml | 6 +++--- README.md | 2 +- src/lib.rs | 27 ++++++++++++++++++--------- src/uuid.rs | 7 +++++-- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bafafd6..3d43103 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,9 @@ readme = "README.md" license-file = "LICENSE.md" repository = "https://git.kittencollective.com/nebkor/julid-rs" +[package.metadata.docs.rs] +all-features = true + [features] default = ["serde", "sqlx"] # just the regular crate serde = ["dep:serde"] @@ -51,6 +54,3 @@ harness = false [[bin]] name = "julid-gen" path = "src/bin/gen.rs" - -[package.metadata.docs.rs] -all-features = true diff --git a/README.md b/README.md index 26f57e5..b579081 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Blog post: As of June of 2025, they can also be converted to and from [version 7 UUIDs](https://www.ietf.org/rfc/rfc9562.html#name-uuid-version-7), though some precision in the -intra-millisecond counter is lost when going to a UUID. +intra-millisecond counter is lost when going to a UUID, via the `uuid` optional feature. ## A slightly deeper look diff --git a/src/lib.rs b/src/lib.rs index c56e525..f04267b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,18 +2,27 @@ use sqlite_loadable::prelude::{c_char, c_uint, sqlite3, sqlite3_api_routines}; mod base32; + +/// Contains the [`Julid`] type, which is publicly exported at the top level. pub mod julid; -#[cfg(feature = "serde")] + /// Serialization into bytes, and deserialization from a variety of formats, /// with Serde (feature `serde` (default)) +#[cfg(feature = "serde")] pub mod serde; -#[cfg(feature = "sqlx")] + /// Traits from the SQLx crate for getting Julids into and out of SQLite /// databases from normal Rust applications. (feature `sqlx` (default)) +#[cfg(feature = "sqlx")] pub mod sqlx; -#[cfg(feature = "uuid")] + /// UUIDv7s are almost as good as Julids, and can be interconverted almost -/// perfectly. +/// perfectly. (feature `uuid` (non-default)) +/// +/// See the [`Julid::as_uuid`] and [`Julid::from_uuid`] methods for +/// converting a Julid to a UUID and constructing a Julid from a UUID +/// respectively. +#[cfg(feature = "uuid")] pub mod uuid; #[doc(inline)] @@ -21,13 +30,13 @@ pub use base32::DecodeError; #[doc(inline)] pub use julid::Julid; -/// The number of bits in a Julid's time portion +/// The number of bits in a Julid's millisecond timestamp (48) pub const TIME_BITS: u8 = 48; -/// The number of bits in the monotonic counter for intra-millisecond IDs +/// The number of bits in the monotonic counter for intra-millisecond IDs (16) pub const COUNTER_BITS: u8 = 16; -/// The number of random bits + bits in the monotonic counter +/// The number of random bits + bits in the monotonic counter (80) pub const UNIQUE_BITS: u8 = 80; -/// The number of fully random bits +/// The number of fully random bits (64) pub const RANDOM_BITS: u8 = 64; /// This `unsafe extern "C"` function is the main entry point into the loadable @@ -52,7 +61,7 @@ pub unsafe extern "C" fn sqlite3_julid_init( } /// The code for the SQLite plugin is kept in this module, and exposed via the -/// `sqlite3_julid_init` function (feature `plugin`) +/// [`sqlite3_julid_init`] function (feature `plugin` (non-default)) #[cfg(feature = "plugin")] pub mod sqlite_plugin { use sqlite_loadable::{ diff --git a/src/uuid.rs b/src/uuid.rs index a62f191..b12bd6a 100644 --- a/src/uuid.rs +++ b/src/uuid.rs @@ -13,7 +13,7 @@ impl Julid { /// means that some bits in the original Julid are overwritten with /// UUID-specific values, but only six bits in total are potentially /// altered. - pub fn as_uuid(&self) -> Uuid { + pub const fn as_uuid(&self) -> Uuid { let counter_mask = (1 << 12) - 1; let entropy_mask = (1 << 62) - 1; let timestamp = self.timestamp(); @@ -29,7 +29,9 @@ impl Julid { /// /// UUIDv7s are very similar to Julids, but use 12 bits for a monotonic /// counter instead of 16, and only 62 bits of entropy vs Julids' 64. - /// Therefore, no bits need to be altered when converting to a Julid. + /// Therefore, no bits technically need to be altered when converting to a + /// Julid, but we zero out the high bits of the counter where the UUID + /// version was stored. pub fn from_uuid(id: Uuid) -> Result { let ver = id.get_version_num(); if ver != 7 { @@ -107,6 +109,7 @@ mod test { assert_eq!(j1.timestamp(), ju1.timestamp()); assert_eq!(j1.counter(), ju1.counter()); assert_eq!(j1.random() << 2, ju1.random() << 2); + assert_eq!(ju1.random() >> 62, 2); // once we've converted to uuid and then back to julid, we've reached the fixed // point let u2 = ju1.as_uuid();