#snowflake-id #id #identifier #entity-id #snowflake #uuid #unique-identifier

tagid

Defines a newtype labeled tagging for different types of ids

1 unstable release

new 0.2.0 Feb 12, 2025

#453 in Data structures

MIT license

120KB
2K SLoC

tagid - Typed Unique Identifiers for Rust Entities

Crates.io Docs.rs License: MIT

tagid provides a robust system for defining and managing typed unique identifiers in Rust.
It supports multiple ID generation strategies (CUID, UUID, Snowflake) and integrates seamlessly with
serde, sqlx, and other frameworks.

Features

  • Typed Identifiers: Define entity-specific IDs with compile-time safety.
  • Multiple ID Generators:
    • CUID (cuid feature) - Compact, collision-resistant IDs.
    • UUID (uuid feature) - Universally unique identifiers.
    • Snowflake (snowflake feature) - Time-based, distributed IDs.
  • Entity Labeling: Labels provide contextual meaning to identifiers.
  • Serialization & Database Support:
    • serde integration for JSON and binary serialization (serde feature).
    • sqlx integration for database storage (sqlx feature).
  • Custom Labeling: Define custom label formats for entities.

Installation

Add tagid to your Cargo.toml, enabling the desired features:

[dependencies]
tagid = { version = "0.1", features = ["uuid", "sqlx"] }

Optional Features

Feature Description
"derive" Enables #[derive(Label)] macro for automatic labeling.
"cuid" Enables the CuidGenerator for CUID-based IDs.
"uuid" Enables the UuidGenerator for UUID-based IDs.
"snowflake" Enables the SnowflakeGenerator for distributed IDs.
"serde" Enables serialization support via serde.
"sqlx" Enables database integration via sqlx.
"envelope" Provides an envelope struct for wrapping IDs with metadata.

Usage

Defining an Entity with a Typed ID

use tagid::{Entity, Id, Label};

#[derive(Label)]
struct User;

impl Entity for User {
    type IdGen = tagid::UuidGenerator;
}

fn main() {
    let user_id = User::next_id();
    println!("User ID: {}", user_id);
}

Labeling System

Labels help associate an identifier with an entity, improving clarity in logs and databases. The Label trait provides a way to define a unique label for each entity type.

use tagid::{Label, Labeling};

#[derive(Label)]
struct Order;

let order_label = Order::labeler().label();
assert_eq!(order_label, "Order");

This ensures that IDs are self-descriptive when displayed, stored, or logged.

Working with Different ID Types

Using CUIDs

Enable the cuid feature in Cargo.toml:

[dependencies]
tagid = { version = "0.2", features = ["cuid"] }

Example usage:

use tagid::{Entity, Id, Label, CuidGenerator};

#[derive(Label)]
struct Session;

impl Entity for Session {
    type IdGen = CuidGenerator;
}

fn main() {
    let session_id = Session::next_id();
    println!("Session ID: {}", session_id);
}

Using UUIDs

Enable the uuid feature:

[dependencies]
tagid = { version = "0.2", features = ["uuid"] }

Example usage:

use tagid::{Entity, Id, Label, UuidGenerator};

#[derive(Label)]
struct User;

impl Entity for User {
    type IdGen = UuidGenerator;
}

fn main() {
    let user_id = User::next_id();
    println!("User ID: {}", user_id);
}

Using Snowflake IDs

Enable the snowflake feature:

[dependencies]
tagid = { version = "0.2", features = ["snowflake"] }

Example usage:

use tagid::{Entity, Id, Label, snowflake::SnowflakeGenerator};

#[derive(Label)]
struct LogEntry;

impl Entity for LogEntry {
    type IdGen = SnowflakeGenerator;
}

fn main() {
    let log_id = LogEntry::next_id();
    println!("Log ID: {}", log_id);
}

Serialization & Database Integration

JSON Serialization with serde

Enable the serde feature in Cargo.toml

[dependencies]
tagid = { version = "0.2", features = ["serde", "derive"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1"

Then serialize an ID:

use tagid::{Entity, Id, Label};
use serde::{Serialize, Deserialize};

#[derive(Label, Serialize, Deserialize)]
struct Product;

impl Entity for Product {
    type IdGen = tagid::UuidGenerator;
}

fn main() {
    let product_id = Product::next_id();
    let serialized = serde_json::to_string(&product_id).unwrap();
    println!("Serialized ID: {}", serialized);
}

SQL Database Integration with sqlx

Enable sqlx support in Cargo.toml:

[dependencies]
tagid = { version = "0.2", features = ["sqlx", "derive"] }
sqlx = { version = "0.7", features = ["postgres"] }

Then use `Is<T, ID> in a database model:

use tagid::{Entity, Id, Label};
use sqlx::FromRow;

#[derive(Label)]
struct Customer;

impl Entity for Customer {
    type IdGen = tagid::UuidGenerator;
}

#[derive(FromRow)]
struct CustomerRecord {
    id: Id<Customer, uuid::Uuid>,
    name: String,
}

Benchmarking

To measure the performance of difference ID generators, run:

cargo bench

Contributing

Contributions are welcome! Open an issue or submit a pull request on GitHub.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Dependencies

~8–17MB
~238K SLoC