Loading page…
Rust walkthroughs
Loading page…
UUID is a crate for generating and parsing Universally Unique Identifiers (UUIDs) in Rust. UUIDs are 128-bit identifiers that are practically unique without requiring a central coordination authority. They're commonly used for database primary keys, session identifiers, and distributed systems.
Key concepts:
UUID Versions:
| Version | Description | Use Case | |---------|-------------|----------| | v1 | Time + MAC address | Legacy, time-ordered | | v4 | Random | General purpose, most common | | v5 | SHA-1 hash + namespace | Deterministic, reproducible | | v7 | Unix timestamp + random | Time-ordered, modern |
When to use UUID:
When NOT to use UUID:
use uuid::Uuid;
fn main() {
// Generate a random UUID (v4)
let id = Uuid::new_v4();
println!("UUID: {}", id);
println!("Hyphenated: {}", id.hyphenated());
println!("Simple (no dashes): {}", id.simple());
println!("URN format: {}", id.urn());
}use uuid::Uuid;
fn main() {
// Nil UUID (all zeros)
let nil = Uuid::nil();
println!("Nil: {}", nil); // 00000000-0000-0000-0000-000000000000
// Max UUID (all ones)
let max = Uuid::max();
println!("Max: {}", max); // ffffffff-ffff-ffff-ffff-ffffffffffff
// Check if nil
assert!(nil.is_nil());
assert!(!max.is_nil());
}use uuid::Uuid;
fn main() {
// Parse from string
let id = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
println!("Parsed: {}", id);
// Parse from simple format (no hyphens)
let id_simple = Uuid::parse_str("550e8400e29b41d4a716446655440000").unwrap();
println!("From simple: {}", id_simple);
// Parse with braces
let id_braced = Uuid::parse_str("{550e8400-e29b-41d4-a716-446655440000}").unwrap();
println!("With braces: {}", id_braced);
// Parse from URN
let id_urn = Uuid::parse_str("urn:uuid:550e8400-e29b-41d4-a716-446655440000").unwrap();
println!("From URN: {}", id_urn);
}use uuid::Uuid;
fn main() {
// v4 is the most common - cryptographically random
let id1 = Uuid::new_v4();
let id2 = Uuid::new_v4();
println!("ID 1: {}", id1);
println!("ID 2: {}", id2);
// Each is unique
assert_ne!(id1, id2);
// Check version
println!("Version: {:?}", id1.get_version()); // Some(Random)
println!("Variant: {:?}", id1.get_variant()); // Some(RFC4122)
}use uuid::Uuid;
fn main() {
// v7 combines timestamp with randomness - time-ordered
let id1 = Uuid::now_v7();
std::thread::sleep(std::time::Duration::from_millis(10));
let id2 = Uuid::now_v7();
println!("ID 1: {}", id1);
println!("ID 2: {}", id2);
// v7 UUIDs sort by time
assert!(id1 < id2);
// Extract timestamp
if let Some(ts) = id1.get_timestamp() {
println!("Timestamp: {:?}", ts);
}
}use uuid::{Uuid, uuid5};
fn main() {
// v5 generates deterministic UUIDs from a namespace and name
// Same namespace + name = same UUID
// DNS namespace
let dns_namespace = Uuid::NAMESPACE_DNS;
let id1 = Uuid::new_v5(dns_namespace, b"example.com");
let id2 = Uuid::new_v5(dns_namespace, b"example.com");
println!("UUID for example.com: {}", id1);
// Same input = same output
assert_eq!(id1, id2);
// Different name = different UUID
let id3 = Uuid::new_v5(dns_namespace, b"other.com");
assert_ne!(id1, id3);
}use uuid::Uuid;
fn main() {
// v1 uses timestamp and node ID
// Requires "v1" feature and clock sequence
// Simple approach with random node
let id = Uuid::now_v1(&[1, 2, 3, 4, 5, 6]);
println!("v1 UUID: {}", id);
// Get timestamp
if let Some(ts) = id.get_timestamp() {
let (seconds, nanos) = ts.to_unix();
println!("Unix time: {}.{:09}", seconds, nanos);
}
}use uuid::Uuid;
fn main() {
// From bytes (big-endian)
let bytes: [u8; 16] = [
0x55, 0x0e, 0x84, 0x00,
0xe2, 0x9b,
0x41, 0xd4,
0xa7, 0x16,
0x44, 0x66, 0x55, 0x44, 0x00, 0x00
];
let id = Uuid::from_bytes(bytes);
println!("From bytes: {}", id);
// From 128-bit integer
let num: u128 = 0x550e8400_e29b_41d4_a716_446655440000;
let id = Uuid::from_u128(num);
println!("From u128: {}", id);
// Get bytes back
let bytes = id.as_bytes();
println!("Bytes: {:02x?}", bytes);
// Get u128
let num = id.as_u128();
println!("As u128: {:032x}", num);
}use serde::{Serialize, Deserialize};
use uuid::Uuid;
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: Uuid,
name: String,
}
fn main() {
let user = User {
id: Uuid::new_v4(),
name: "Alice".to_string(),
};
// Serialize to JSON
let json = serde_json::to_string(&user).unwrap();
println!("JSON: {}", json);
// Deserialize from JSON
let parsed: User = serde_json::from_str(&json).unwrap();
println!("Parsed: {:?}", parsed);
}use uuid::Uuid;
fn main() {
let id = Uuid::new_v4();
// As bytes
let bytes = id.as_bytes();
println!("Bytes length: {}", bytes.len()); // 16
// As fields (for RFC 4122 format)
let (time_low, time_mid, time_hi_and_version,
clock_seq_hi_and_reserved, clock_seq_low, node) = id.as_fields();
println!("Time low: {:08x}", time_low);
println!("Time mid: {:04x}", time_mid);
println!("Time hi: {:04x}", time_hi_and_version);
// As u64 pair
let (high, low) = id.as_u64_pair();
println!("High: {:016x}, Low: {:016x}", high, low);
}use uuid::Uuid;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Product {
id: Uuid,
name: String,
price: f64,
}
impl Product {
fn new(name: String, price: f64) -> Self {
Self {
id: Uuid::new_v4(),
name,
price,
}
}
}
fn main() {
let product = Product::new("Widget".to_string(), 29.99);
println!("Product: {:?}", product);
}use uuid::Uuid;
use std::collections::HashMap;
struct Session {
user_id: u64,
created_at: std::time::Instant,
}
class SessionManager {
sessions: HashMap<Uuid, Session>,
fn new() -> Self {
Self {
sessions: HashMap::new(),
}
}
fn create_session(&mut self, user_id: u64) -> Uuid {
let token = Uuid::new_v4();
self.sessions.insert(token, Session {
user_id,
created_at: std::time::Instant::now(),
});
token
}
fn get_user(&self, token: &Uuid) -> Option<u64> {
self.sessions.get(token).map(|s| s.user_id)
}
fn remove_session(&mut self, token: &Uuid) {
self.sessions.remove(token);
}
}
fn main() {
let mut manager = SessionManager::new();
let token = manager.create_session(42);
println!("Session token: {}", token);
if let Some(user_id) = manager.get_user(&token) {
println!("User ID: {}", user_id);
}
manager.remove_session(&token);
}use uuid::Uuid;
use std::thread;
fn process_request(request_id: Uuid, data: &str) {
println!("[{}] Processing: {}", request_id, data);
// Pass ID through call stack
validate(&request_id, data);
save(&request_id, data);
}
fn validate(request_id: &Uuid, data: &str) {
println!("[{}] Validating", request_id);
}
fn save(request_id: &Uuid, data: &str) {
println!("[{}] Saving", request_id);
}
fn main() {
let request_id = Uuid::new_v4();
process_request(request_id, "test data");
}use uuid::Uuid;
fn short_id(id: &Uuid) -> String {
id.simple().to_string()[..8].to_string()
}
fn main() {
let id = Uuid::new_v4();
println!("Full UUID: {}", id);
println!("Short ID: {}", short_id(&id));
// Useful for logs, display
// Note: Not unique! Use only for display
}use uuid::Uuid;
fn main() {
let id1 = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
let id2 = Uuid::parse_str("00000000-0000-0000-0000-000000000002").unwrap();
let id3 = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
// Comparison
assert!(id1 < id2);
assert_eq!(id1, id3);
// Sorting (v7 UUIDs are time-ordered)
let v7_1 = Uuid::now_v7();
std::thread::sleep(std::time::Duration::from_millis(1));
let v7_2 = Uuid::now_v7();
let mut ids = vec![v7_2, v7_1];
ids.sort();
assert_eq!(ids, vec![v7_1, v7_2]);
}use uuid::Uuid;
use std::collections::HashMap;
fn main() {
let mut map: HashMap<Uuid, String> = HashMap::new();
let id1 = Uuid::new_v4();
let id2 = Uuid::new_v4();
map.insert(id1, "First".to_string());
map.insert(id2, "Second".to_string());
// Lookup by UUID
if let Some(value) = map.get(&id1) {
println!("Found: {}", value);
}
}use uuid::Uuid;
use base64::{Engine as _, engine::general_purpose};
fn uuid_to_base64(id: &Uuid) -> String {
general_purpose::URL_SAFE_NO_PAD.encode(id.as_bytes())
}
fn base64_to_uuid(encoded: &str) -> Option<Uuid> {
let bytes = general_purpose::URL_SAFE_NO_PAD.decode(encoded).ok()?;
let arr: [u8; 16] = bytes.try_into().ok()?;
Some(Uuid::from_bytes(arr))
}
fn main() {
let id = Uuid::new_v4();
let encoded = uuid_to_base64(&id);
println!("Base64: {}", encoded); // 22 characters instead of 36
let decoded = base64_to_uuid(&encoded).unwrap();
assert_eq!(id, decoded);
}use uuid::Uuid;
fn generate_batch(count: usize) -> Vec<Uuid> {
(0..count).map(|_| Uuid::new_v4()).collect()
}
fn main() {
let ids = generate_batch(5);
for id in &ids {
println!("UUID: {}", id);
}
// All unique
let unique: std::collections::HashSet<_> = ids.iter().collect();
assert_eq!(unique.len(), 5);
}use uuid::Uuid;
fn is_valid_uuid(s: &str) -> bool {
Uuid::parse_str(s).is_ok()
}
fn main() {
let test_cases = [
("550e8400-e29b-41d4-a716-446655440000", true),
("550e8400e29b41d4a716446655440000", true),
("invalid", false),
("550e8400-e29b-41d4-a716", false), // Too short
];
for (input, expected) in test_cases {
let result = is_valid_uuid(input);
println!("{}: {} (expected {})", input, result, expected);
}
}use uuid::Uuid;
fn parse_uuid(input: &str) -> Result<Uuid, uuid::Error> {
Uuid::parse_str(input)
}
fn main() {
match parse_uuid("550e8400-e29b-41d4-a716-446655440000") {
Ok(id) => println!("Parsed: {}", id),
Err(e) => eprintln!("Error: {}", e),
}
match parse_uuid("not-a-uuid") {
Ok(id) => println!("Parsed: {}", id),
Err(e) => eprintln!("Expected error: {}", e),
}
}use uuid::Uuid;
fn main() {
// Fixed UUID for testing
let test_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
// Or use constants
const MY_UUID: &str = "550e8400-e29b-41d4-a716-446655440000";
let id = Uuid::parse_str(MY_UUID).unwrap();
println!("Test UUID: {}", test_id);
println!("Constant UUID: {}", id);
}use uuid::Uuid;
fn main() {
let id1 = Uuid::new_v4();
let id2 = id1; // Copy (UUID is Copy)
assert_eq!(id1, id2);
// Works in functions
fn print_uuid(id: Uuid) { // Takes by value (Copy)
println!("UUID: {}", id);
}
print_uuid(id1);
print_uuid(id1); // Can use again
}UUID Key Imports:
use uuid::Uuid;Generation Methods:
| Method | Version | Description |
|--------|---------|-------------|
| Uuid::new_v4() | v4 | Random UUID |
| Uuid::new_v5(ns, name) | v5 | Deterministic from namespace + name |
| Uuid::now_v7() | v7 | Time-ordered UUID |
| Uuid::now_v1(node) | v1 | Time + node |
| Uuid::nil() | - | All zeros |
| Uuid::max() | - | All ones |
Standard Namespaces (for v5):
| Constant | Description |
|----------|-------------|
| NAMESPACE_DNS | DNS names |
| NAMESPACE_URL | URLs |
| NAMESPACE_OID | ISO OIDs |
| NAMESPACE_X500 | X.500 DN |
Output Formats:
let id = Uuid::new_v4();
id.hyphenated(); // "550e8400-e29b-41d4-a716-446655440000"
id.simple(); // "550e8400e29b41d4a716446655440000"
id.urn(); // "urn:uuid:550e8400-..."
id.braced(); // "{550e8400-...}"Parsing:
// All these work:
Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
Uuid::parse_str("550e8400e29b41d4a716446655440000").unwrap();
Uuid::parse_str("{550e8400-e29b-41d4-a716-446655440000}").unwrap();
Uuid::parse_str("urn:uuid:550e8400-e29b-41d4-a716-446655440000").unwrap();Key Points:
Copy, Clone, Hash, Eq, OrdUuid::nil() for null placeholderserde feature for serialization