Loading page…
Rust walkthroughs
Loading page…
uuid::Uuid::new_v5 (namespace-based) vs uuid::Uuid::new_v4 (random)?uuid::Uuid::new_v4 generates random UUIDs using a cryptographically secure random number generator, providing uniqueness through randomness. uuid::Uuid::new_v5 generates deterministic UUIDs from a namespace identifier and a name, producing the same UUID for the same inputs every time. Use new_v4 when you need unique identifiers with no predictable relationship between them. Use new_v5 when you need reproducible identifiers, want to avoid storing generated IDs, or need to derive IDs from existing data without collision risk across different namespaces.
use uuid::Uuid;
fn generate_random_uuids() {
// v4: Random UUIDs
let id1 = Uuid::new_v4();
let id2 = Uuid::new_v4();
let id3 = Uuid::new_v4();
println!("ID 1: {}", id1); // e.g., "550e8400-e29b-41d4-a716-446655440000"
println!("ID 2: {}", id2); // Different random UUID
println!("ID 3: {}", id3); // Different random UUID
// Each call produces a different UUID
assert_ne!(id1, id2);
assert_ne!(id2, id3);
// Version 4 UUIDs have specific bit patterns
// The version nibble is 4 (0b0100)
// The variant bits are 10xx
}new_v4 generates a different UUID each time using random bytes.
use uuid::{Uuid, uuid};
fn generate_namespace_uuids() {
// v5: Namespace-based UUIDs
// Requires a namespace UUID and a name
// Standard namespaces provided by the uuid crate
use uuid::UuidNamespace;
// DNS namespace - for domain names
let dns_uuid = Uuid::new_v5(&UuidNamespace::DNS, b"example.com");
println!("DNS UUID: {}", dns_uuid);
// URL namespace - for URLs
let url_uuid = Uuid::new_v5(&UuidNamespace::URL, b"https://example.com/page");
println!("URL UUID: {}", url_uuid);
// OID namespace - for object identifiers
let oid_uuid = Uuid::new_v5(&UuidNamespace::OID, b"2.16.840.1.113883.19.4");
println!("OID UUID: {}", oid_uuid);
// X500 namespace - for X.500 DNs
let x500_uuid = Uuid::new_v5(&UuidNamespace::X500, b"cn=John Doe,ou=People");
println!("X500 UUID: {}", x500_uuid);
}new_v5 produces deterministic UUIDs from namespace and name inputs.
use uuid::{Uuid, UuidNamespace};
fn determinism_demo() {
// v4: Non-deterministic
let random1 = Uuid::new_v4();
let random2 = Uuid::new_v4();
assert_ne!(random1, random2); // Always different
// v5: Deterministic - same inputs = same output
let ns_uuid = Uuid::NAMESPACE_DNS;
let name = b"example.com";
let derived1 = Uuid::new_v5(&ns_uuid, name);
let derived2 = Uuid::new_v5(&ns_uuid, name);
assert_eq!(derived1, derived2); // Always the same!
// Different name = different UUID
let other_name = b"other.com";
let derived3 = Uuid::new_v5(&ns_uuid, other_name);
assert_ne!(derived1, derived3);
// Different namespace = different UUID (even with same name)
let other_ns = Uuid::NAMESPACE_URL;
let derived4 = Uuid::new_v5(&other_ns, name);
assert_ne!(derived1, derived4);
}v5 determinism enables reproducible ID generation without storage.
use uuid::{Uuid, UuidNamespace};
fn collision_properties() {
// v4: Collision resistance through randomness
// 122 random bits = extremely low collision probability
// Need ~2^61 UUIDs for 50% collision chance
// Collisions are possible but astronomically unlikely
let id1 = Uuid::new_v4();
let id2 = Uuid::new_v4();
// Probability of id1 == id2: 1 in 5.3 × 10^36
// v5: Collision resistance through namespace separation
// Same namespace + same name = same UUID (by design)
// Different namespaces prevent cross-domain collisions
// These can never collide:
let dns_id = Uuid::new_v5(&Uuid::NAMESPACE_DNS, b"example.com");
let url_id = Uuid::new_v5(&Uuid::NAMESPACE_URL, b"example.com");
assert_ne!(dns_id, url_id);
// These can never collide:
let id_a = Uuid::new_v5(&Uuid::NAMESPACE_DNS, b"example.com");
let id_b = Uuid::new_v5(&Uuid::NAMESPACE_DNS, b"example.org");
assert_ne!(id_a, id_b);
// SHA-1 hash collision is the only way for same namespace
// SHA-1 collisions are computationally infeasible
}v4 uses randomness for uniqueness; v5 uses SHA-1 hashing with namespace separation.
use uuid::{Uuid, UuidNamespace};
struct Application {
// Custom namespace for this application
app_namespace: Uuid,
}
impl Application {
fn new() -> Self {
// Create a namespace UUID for your application
// This should be a fixed, known UUID
Self {
app_namespace: uuid!("6ba7b810-9dad-11d1-80b4-00c04fd430c8"),
}
}
// v5: Derive user ID from email - no storage needed
fn user_id_from_email(&self, email: &str) -> Uuid {
Uuid::new_v5(&self.app_namespace, email.as_bytes())
}
// Same email always produces the same user ID
fn demo(&self) {
let email = "user@example.com";
let id1 = self.user_id_from_email(email);
let id2 = self.user_id_from_email(email);
assert_eq!(id1, id2); // Deterministic!
// Can reconstruct user ID from email at any time
// No database lookup needed to get the ID
}
}
// v4 approach requires storage
fn v4_user_ids() {
use std::collections::HashMap;
let mut email_to_id: HashMap<String, Uuid> = HashMap::new();
// Must generate and store the mapping
let email = "user@example.com".to_string();
let id = Uuid::new_v4();
email_to_id.insert(email.clone(), id);
// Later, must look up the ID
let retrieved_id = email_to_id.get(&email);
}v5 enables deriving IDs from data without storing the mapping.
use uuid::{Uuid, UuidNamespace};
fn url_based_ids() {
// v5: Generate IDs for web resources
let url = "https://api.example.com/articles/123";
let resource_id = Uuid::new_v5(&Uuid::NAMESPACE_URL, url.as_bytes());
println!("Resource ID: {}", resource_id);
// Same URL always maps to same ID
// Different systems can generate the same ID independently
// Use case: Distributed systems generating IDs for web resources
// without coordination
}
struct ContentCache {
url_namespace: Uuid,
}
impl ContentCache {
fn content_id(&self, url: &str) -> Uuid {
// Derive cache key from URL
Uuid::new_v5(&self.url_namespace, url.as_bytes())
}
fn store(&self, url: &str, content: &[u8]) {
let id = self.content_id(url);
// Store with derived ID - no URL->ID mapping needed
}
fn retrieve(&self, url: &str) -> Option<Vec<u8>> {
let id = self.content_id(url);
// Retrieve using derived ID - reconstruct from URL
// ... implementation
None
}
}v5 is ideal for deriving IDs from URLs in distributed systems.
use uuid::{Uuid, uuid};
// Scenario: Multiple services need consistent IDs
// v5 enables independent ID generation without coordination
const ORDER_NAMESPACE: Uuid = uuid!("6ba7b810-9dad-11d1-80b4-00c04fd43001");
const CUSTOMER_NAMESPACE: Uuid = uuid!("6ba7b810-9dad-11d1-80b4-00c04fd43002");
fn distributed_order_system() {
// Service A generates order ID from order number
let order_number = "ORD-2024-001234";
let order_id_a = Uuid::new_v5(&ORDER_NAMESPACE, order_number.as_bytes());
// Service B independently generates the same ID
let order_id_b = Uuid::new_v5(&ORDER_NAMESPACE, order_number.as_bytes());
assert_eq!(order_id_a, order_id_b);
// No coordination needed!
// Customer ID derived from customer email
let email = "customer@example.com";
let customer_id = Uuid::new_v5(&CUSTOMER_NAMESPACE, email.as_bytes());
// Order and customer IDs can't collide (different namespaces)
assert_ne!(order_id_a, customer_id);
}
// v4 would require coordination
fn v4_distributed_needs_coordination() {
// Option 1: Central ID generation service
// Option 2: Database sequence
// Option 3: Pre-allocated ID ranges
// All require coordination or single point of failure
}v5 enables coordination-free consistent ID generation across services.
use uuid::{Uuid, uuid};
const USER_NAMESPACE: Uuid = uuid!("6ba7b810-9dad-11d1-80b4-00c04fd43003");
fn privacy_sensitive_ids() {
// v4: Random IDs don't expose source data
let user_id_v4 = Uuid::new_v4();
// Can't determine who this ID belongs to from the UUID
// v5: ID is derived from source data
let email = "sensitive@example.com";
let user_id_v5 = Uuid::new_v5(&USER_NAMESPACE, email.as_bytes());
// Security consideration: Can someone reverse-engineer the email?
// SHA-1 is one-way, but they could brute-force common emails
// Recommendation: Use a private namespace
let private_namespace = Uuid::new_v4(); // Generated once, kept secret
let secure_id = Uuid::new_v5(&private_namespace, email.as_bytes());
// Without knowing private_namespace, can't brute-force effectively
}
struct SecureIdGenerator {
private_namespace: Uuid,
}
impl SecureIdGenerator {
fn new() -> Self {
// Generate once at deployment, store securely
Self {
private_namespace: Uuid::new_v4(),
}
}
fn generate_id(&self, source: &str) -> Uuid {
Uuid::new_v5(&self.private_namespace, source.as_bytes())
}
}v5 can leak information about source data; use private namespaces for security.
use uuid::{Uuid, uuid};
// v5: Create public IDs from private data without exposing the data
const PUBLIC_ID_NAMESPACE: Uuid = uuid!("6ba7b810-9dad-11d1-80b4-00c04fd43004");
fn anonymous_ids() {
// Internal employee ID (private)
let employee_id = "EMP-12345";
// Public-facing ID (derived, but not reversible)
let public_id = Uuid::new_v5(&PUBLIC_ID_NAMESPACE, employee_id.as_bytes());
// Benefits:
// 1. Same employee always gets same public ID
// 2. Can generate public ID without database lookup
// 3. Public ID doesn't reveal internal structure
// Example: Public profile URLs
let profile_url = format!("https://example.com/profile/{}", public_id);
println!("Profile: {}", profile_url);
// If someone tries to enumerate employees,
// they'd need to know the internal IDs first
}v5 creates consistent public IDs from private identifiers.
use uuid::Uuid;
fn v4_use_cases() {
// Use v4 when:
// 1. Creating new entities with no natural key
let session_id = Uuid::new_v4();
let transaction_id = Uuid::new_v4();
let event_id = Uuid::new_v4();
// 2. Need unpredictability for security
let api_key = Uuid::new_v4();
let reset_token = Uuid::new_v4();
// 3. No natural source data to derive from
let message_id = Uuid::new_v4();
// 4. Want to prevent enumeration attacks
let order_id = Uuid::new_v4(); // Can't guess other order IDs
// 5. Simple case - just need a unique identifier
let id = Uuid::new_v4();
}Use v4 when you need unique, unpredictable identifiers with no derivation logic.
use uuid::{Uuid, uuid};
const NAMESPACE: Uuid = uuid!("6ba7b810-9dad-11d1-80b4-00c04fd43005");
fn v5_use_cases() {
// Use v5 when:
// 1. Deriving IDs from existing unique data
let email = "user@example.com";
let user_id = Uuid::new_v5(&NAMESPACE, email.as_bytes());
// 2. Reproducible IDs across systems
// Both systems generate same ID without communication
let document_url = "https://docs.example.com/spec";
let doc_id = Uuid::new_v5(&Uuid::NAMESPACE_URL, document_url.as_bytes());
// 3. Avoiding ID storage
// Can reconstruct ID from source data
let filename = "report-2024.pdf";
let file_id = Uuid::new_v5(&NAMESPACE, filename.as_bytes());
// 4. Content-addressed storage
let content_hash = "sha256:abc123...";
let content_id = Uuid::new_v5(&NAMESPACE, content_hash.as_bytes());
// 5. Merging data from different sources
// Same entity gets same ID regardless of import order
let external_id = "EXT-12345";
let internal_id = Uuid::new_v5(&NAMESPACE, external_id.as_bytes());
}Use v5 when determinism and reproducibility are valuable.
use uuid::{Uuid, uuid};
// Define application-specific namespaces
const MY_APP_NAMESPACE: Uuid = uuid!("f47ac10b-58cc-4372-a567-0e02b2c3d479");
const MY_APP_USERS: Uuid = uuid!("f47ac10b-58cc-4372-a567-0e02b2c3d480");
const MY_APP_PRODUCTS: Uuid = uuid!("f47ac10b-58cc-4372-a567-0e02b2c3d481");
const MY_APP_ORDERS: Uuid = uuid!("f47ac10b-58cc-4372-a567-0e02b2c3d482");
fn custom_namespaces() {
// Users namespace
let user_email = "alice@example.com";
let user_id = Uuid::new_v5(&MY_APP_USERS, user_email.as_bytes());
// Products namespace - same source data, different ID
let product_sku = "alice@example.com"; // Hypothetically same string
let product_id = Uuid::new_v5(&MY_APP_PRODUCTS, product_sku.as_bytes());
// Different namespaces prevent collisions
assert_ne!(user_id, product_id);
// Even though the input strings are the same!
// Orders namespace
let order_number = "2024-001234";
let order_id = Uuid::new_v5(&MY_APP_ORDERS, order_number.as_bytes());
}Create custom namespaces to organize ID domains and prevent collisions.
use uuid::Uuid;
fn version_identification() {
let v4_id = Uuid::new_v4();
let v5_id = Uuid::new_v5(&Uuid::NAMESPACE_DNS, b"example.com");
// Check version
println!("v4 version: {:?}", v4_id.get_version()); // Some(Random)
println!("v5 version: {:?}", v5_id.get_version()); // Some(Sha1)
// Version is encoded in the UUID
// v4: 4 in the version position (6th octet, high nibble)
// v5: 5 in the version position
// Can identify UUID type from the value itself
assert_eq!(v4_id.get_version(), Some(uuid::Version::Random));
assert_eq!(v5_id.get_version(), Some(uuid::Version::Sha1));
}UUID versions are encoded in the identifier, allowing detection of the generation method.
use uuid::{Uuid, uuid};
const NAMESPACE: Uuid = uuid!("f47ac10b-58cc-4372-a567-0e02b2c3d479");
struct IdStrategy {
namespace: Uuid,
}
impl IdStrategy {
// v5 for known entities
fn user_id(&self, email: &str) -> Uuid {
Uuid::new_v5(&self.namespace, email.as_bytes())
}
// v4 for new entities with no natural key
fn session_id(&self) -> Uuid {
Uuid::new_v4()
}
// v5 derived from multiple fields
fn composite_id(&self, user_id: Uuid, resource_type: &str, resource_id: &str) -> Uuid {
let mut input = Vec::new();
input.extend_from_slice(user_id.as_bytes());
input.extend_from_slice(resource_type.as_bytes());
input.extend_from_slice(resource_id.as_bytes());
Uuid::new_v5(&self.namespace, &input)
}
// v5 with timestamp for versioning
fn versioned_id(&self, base: &str, version: u32) -> Uuid {
let input = format!("{}:v{}", base, version);
Uuid::new_v5(&self.namespace, input.as_bytes())
}
}Combine v4 and v5 based on entity characteristics.
use uuid::{Uuid, uuid};
fn performance_comparison() {
use std::time::Instant;
const NAMESPACE: Uuid = uuid!("f47ac10b-58cc-4372-a567-0e02b2c3d479");
// v4: Just random bytes
let start = Instant::now();
for _ in 0..10_000 {
let _ = Uuid::new_v4();
}
let v4_duration = start.elapsed();
println!("v4: {:?}", v4_duration);
// v5: SHA-1 hash computation
let start = Instant::now();
for i in 0..10_000 {
let input = format!("item-{}", i);
let _ = Uuid::new_v5(&NAMESPACE, input.as_bytes());
}
let v5_duration = start.elapsed();
println!("v5: {:?}", v5_duration);
// v5 is slower due to SHA-1 computation
// But for most applications, the difference is negligible
// The determinism benefit often outweighs the performance cost
}v5 has SHA-1 computation overhead; v4 is faster but requires storage for determinism.
| Characteristic | v4 (Random) | v5 (Namespace) | |---------------|-------------|----------------| | Determinism | No | Yes | | Uniqueness | Probabilistic | Cryptographic hash | | Coordination | Not needed | Not needed | | Predictability | Unpredictable | Deterministic | | Storage needed | Yes (for lookup) | No (derivable) | | Performance | Faster | SHA-1 overhead | | Enumeration safe | Yes | Depends on inputs | | Collision risk | Very low | Depends on inputs | | Use for secrets | Yes | Be careful |
The choice between new_v4 and new_v5 depends on whether you need randomness or determinism:
Use Uuid::new_v4 when:
Use Uuid::new_v5 when:
Key insight: v5 trades unpredictability for determinism. If you can derive an ID from existing data and that determinism is valuable (no storage, no coordination, reproducibility), use v5. If you need true uniqueness without any relationship to source data, or unpredictability for security, use v4. The namespace in v5 serves as a domain separator, allowing the same source string to produce different IDs in different contexts—use this to organize your ID spaces and prevent unintended collisions across entity types.