Update docs, tests, and improve conversion to UUIDs.

This commit is contained in:
Joe Ardent 2025-06-26 17:46:09 -07:00
parent 02b99ba010
commit 8bbad764c3
4 changed files with 27 additions and 15 deletions

View file

@ -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

View file

@ -32,7 +32,7 @@ Blog post: <https://proclamations.nebcorp-hias.com/sundries/presenting-julids/>
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

View file

@ -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::{

View file

@ -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<Self, UuidError> {
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();