Loading page…
Rust walkthroughs
Loading page…
The uuid crate provides a complete implementation of Universally Unique Identifiers (UUIDs) as defined in RFC 4122. UUIDs are 128-bit identifiers that are practically unique without requiring a central authority. They're commonly used for database primary keys, session identifiers, distributed system IDs, and anywhere you need unique identifiers that don't need to be sequential.
Key concepts:
# Cargo.toml
[dependencies]
uuid = { version = "1.0", features = ["v4", "fast-rng"] }use uuid::Uuid;
fn main() {
// Generate a random UUID (v4)
let id = Uuid::new_v4();
println!("Random UUID: {}", id);
// Parse from string
let parsed = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
println!("Parsed UUID: {}", parsed);
// Get version
println!("Version: {:?}", parsed.get_version());
}use uuid::Uuid;
fn main() {
// v4: Random UUID (most common)
let v4 = Uuid::new_v4();
println!("v4 (random): {}", v4);
// v7: Time-ordered UUID (newer, recommended for databases)
// Requires "v7" feature
#[cfg(feature = "v7")]
{
let v7 = Uuid::now_v7();
println!("v7 (time-ordered): {}", v7);
}
// v3: Name-based (MD5)
// Requires "v3" feature
#[cfg(feature = "v3")]
{
let namespace = Uuid::NAMESPACE_DNS;
let v3 = Uuid::new_v3(namespace, b"example.com");
println!("v3 (MD5): {}", v3);
}
// v5: Name-based (SHA-1)
// Requires "v5" feature
#[cfg(feature = "v5")]
{
let namespace = Uuid::NAMESPACE_DNS;
let v5 = Uuid::new_v5(namespace, b"example.com");
println!("v5 (SHA-1): {}", v5);
}
// Nil UUID (all zeros)
let nil = Uuid::nil();
println!("Nil UUID: {}", nil);
println!("Is nil: {}", nil.is_nil());
}use uuid::Uuid;
fn main() {
// Parse standard hyphenated format
let from_hyphenated = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
println!("Parsed: {}", from_hyphenated);
// Parse simple format (no hyphens)
let from_simple = Uuid::parse_str("550e8400e29b41d4a716446655440000").unwrap();
println!("From simple: {}", from_simple);
// Parse URN format
let from_urn = Uuid::parse_str("urn:uuid:550e8400-e29b-41d4-a716-446655440000").unwrap();
println!("From URN: {}", from_urn);
// Parse with braces
let from_braced = Uuid::parse_str("{550e8400-e29b-41d4-a716-446655440000}").unwrap();
println!("From braced: {}", from_braced);
// All parsed to the same UUID
assert_eq!(from_hyphenated, from_simple);
assert_eq!(from_hyphenated, from_urn);
assert_eq!(from_hyphenated, from_braced);
// Handle parse errors
match Uuid::parse_str("invalid-uuid") {
Ok(uuid) => println!("Parsed: {}", uuid),
Err(e) => println!("Parse error: {}", e),
}
}use uuid::Uuid;
fn main() {
let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
// Default Display (hyphenated, lowercase)
let hyphenated = uuid.to_string();
println!("Hyphenated: {}", hyphenated);
// Hyphenated, uppercase
let hyphenated_upper = uuid.hyphenated().to_string();
println!("Hyphenated (upper): {}", hyphenated_upper.to_uppercase());
// Simple format (no hyphens)
let simple = uuid.simple().to_string();
println!("Simple: {}", simple);
// URN format
let urn = uuid.urn().to_string();
println!("URN: {}", urn);
// Braced format
let braced = uuid.braced().to_string();
println!("Braced: {}", braced);
}use uuid::Uuid;
fn main() {
let uuid = Uuid::new_v4();
// Convert to bytes (16-byte array)
let bytes = uuid.as_bytes();
println!("Bytes: {:02x?}", bytes);
println!("Length: {} bytes", bytes.len());
// Create from bytes
let from_bytes = Uuid::from_bytes(bytes);
assert_eq!(uuid, from_bytes);
// Create from bytes slice
let bytes_slice: [u8; 16] = [
0x55, 0x0e, 0x84, 0x00,
0xe2, 0x9b,
0x41, 0xd4,
0xa7, 0x16,
0x44, 0x66, 0x55, 0x44, 0x00, 0x00,
];
let from_slice = Uuid::from_bytes_ref(&bytes_slice);
println!("From slice: {}", from_slice);
// Convert to u128
let as_u128 = uuid.as_u128();
println!("As u128: {}", as_u128);
// Create from u128
let from_u128 = Uuid::from_u128(as_u128);
assert_eq!(uuid, from_u128);
// Convert to two u64 values (high and low)
let (high, low) = (uuid.as_u64_pair());
println!("High: {}, Low: {}", high, low);
}use uuid::{Uuid, Version, Variant};
fn main() {
let v4 = Uuid::new_v4();
println!("v4 UUID: {}", v4);
// Get version
println!("Version: {:?}", v4.get_version());
// Get variant
println!("Variant: {:?}", v4.get_variant());
// Check version-specific properties
match v4.get_version() {
Some(Version::Random) => println!("This is a random UUID"),
Some(Version::Mac) => println!("This is a MAC-based UUID"),
Some(Version::Md5) => println!("This is an MD5 name-based UUID"),
Some(Version::Sha1) => println!("This is a SHA-1 name-based UUID"),
Some(Version::SortRand) => println!("This is a time-ordered UUID"),
_ => println!("Other version"),
}
// Compare UUIDs
let another = Uuid::new_v4();
println!("\nComparing UUIDs:");
println!("Equal: {}", v4 == another);
println!("Not equal: {}", v4 != another);
// Ordering
let uuids = vec![another, v4];
let mut sorted = uuids;
sorted.sort();
println!("Sorted: {}", sorted[0] < sorted[1]);
}use uuid::Uuid;
fn main() {
// Standard namespaces
println!("Standard namespaces:");
println!(" DNS: {}", Uuid::NAMESPACE_DNS);
println!(" URL: {}", Uuid::NAMESPACE_URL);
println!(" OID: {}", Uuid::NAMESPACE_OID);
println!(" X500: {}", Uuid::NAMESPACE_X500);
// v5: SHA-1 based (recommended over v3)
let user_id = Uuid::new_v5(Uuid::NAMESPACE_DNS, b"user@example.com");
println!("\nUser ID (v5): {}", user_id);
// Same input = same UUID
let same_user_id = Uuid::new_v5(Uuid::NAMESPACE_DNS, b"user@example.com");
assert_eq!(user_id, same_user_id);
println!("Deterministic: same input always produces same UUID");
// Different namespace = different UUID
let url_user_id = Uuid::new_v5(Uuid::NAMESPACE_URL, b"user@example.com");
assert_ne!(user_id, url_user_id);
println!("Different namespace produces different UUID");
// Custom namespace
let my_namespace = Uuid::new_v4();
let custom_id = Uuid::new_v5(my_namespace, b"my-data");
println!("\nCustom namespace: {}", my_namespace);
println!("Custom ID: {}", custom_id);
// Example: Generate consistent IDs for records
let records = vec!["alice", "bob", "charlie"];
let namespace = Uuid::NAMESPACE_DNS;
println!("\nRecord IDs:");
for record in records {
let id = Uuid::new_v5(namespace, record.as_bytes());
println!(" {}: {}", record, id);
}
}use uuid::Uuid;
use std::collections::HashMap;
#[derive(Debug, Clone)]
struct User {
id: Uuid,
username: String,
email: String,
}
impl User {
fn new(username: String, email: String) -> Self {
Self {
id: Uuid::new_v4(),
username,
email,
}
}
fn with_id(id: Uuid, username: String, email: String) -> Self {
Self { id, username, email }
}
}
struct UserStore {
users: HashMap<Uuid, User>,
}
impl UserStore {
fn new() -> Self {
Self {
users: HashMap::new(),
}
}
fn create_user(&mut self, username: String, email: String) -> Uuid {
let user = User::new(username, email);
let id = user.id;
self.users.insert(id, user);
id
}
fn get_user(&self, id: &Uuid) -> Option<&User> {
self.users.get(id)
}
fn delete_user(&mut self, id: &Uuid) -> Option<User> {
self.users.remove(id)
}
}
fn main() {
let mut store = UserStore::new();
// Create users
let alice_id = store.create_user("alice".to_string(), "alice@example.com".to_string());
let bob_id = store.create_user("bob".to_string(), "bob@example.com".to_string());
println!("Created users:");
println!(" Alice: {}", alice_id);
println!(" Bob: {}", bob_id);
// Get user
if let Some(user) = store.get_user(&alice_id) {
println!("\nFound: {:?}", user);
}
// Parse ID from string
let id_str = alice_id.to_string();
if let Ok(parsed_id) = Uuid::parse_str(&id_str) {
if let Some(user) = store.get_user(&parsed_id) {
println!("Found by parsed ID: {}", user.username);
}
}
}// Requires: uuid = { version = "1.0", features = ["v4", "serde"] }
use uuid::Uuid;
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Document {
id: Uuid,
title: String,
content: String,
}
fn main() {
// Create document
let doc = Document {
id: Uuid::new_v4(),
title: "My Document".to_string(),
content: "Hello, World!".to_string(),
};
// Serialize to JSON
let json = serde_json::to_string(&doc).unwrap();
println!("JSON: {}", json);
// Deserialize from JSON
let parsed: Document = serde_json::from_str(&json).unwrap();
println!("Parsed: {:?}", parsed);
// The UUID is serialized as a string by default
assert!(json.contains('"'));
}use uuid::Uuid;
// Simulated database operations
#[derive(Debug, Clone)]
struct Record {
id: Uuid,
data: String,
}
struct Database {
records: Vec<Record>,
}
impl Database {
fn new() -> Self {
Self { records: Vec::new() }
}
fn insert(&mut self, data: String) -> Uuid {
let record = Record {
id: Uuid::new_v4(),
data,
};
let id = record.id;
self.records.push(record);
id
}
fn find(&self, id: Uuid) -> Option<&Record> {
self.records.iter().find(|r| r.id == id)
}
fn delete(&mut self, id: Uuid) -> bool {
let len = self.records.len();
self.records.retain(|r| r.id != id);
self.records.len() < len
}
}
fn main() {
let mut db = Database::new();
// Insert records
let id1 = db.insert("First record".to_string());
let id2 = db.insert("Second record".to_string());
println!("Inserted records:");
println!(" ID 1: {}", id1);
println!(" ID 2: {}", id2);
// Find record
if let Some(record) = db.find(id1) {
println!("\nFound: {:?}", record);
}
// Delete record
if db.delete(id1) {
println!("\nDeleted record {}", id1);
}
// Try to find deleted record
if db.find(id1).is_none() {
println!("Record not found (expected)");
}
}use uuid::Uuid;
fn main() {
// Generate multiple UUIDs
let uuids: Vec<Uuid> = (0..5).map(|_| Uuid::new_v4()).collect();
println!("Generated {} UUIDs:", uuids.len());
for (i, id) in uuids.iter().enumerate() {
println!(" {}: {}", i, id);
}
// Check uniqueness
let mut seen = std::collections::HashSet::new();
let all_unique = uuids.iter().all(|id| seen.insert(*id));
println!("\nAll unique: {}", all_unique);
// Performance benchmark
use std::time::Instant;
let count = 100_000;
let start = Instant::now();
let _: Vec<Uuid> = (0..count).map(|_| Uuid::new_v4()).collect();
let duration = start.elapsed();
println!("\nGenerated {} UUIDs in {:?}", count, duration);
println!("Rate: {:.0} UUIDs/sec", count as f64 / duration.as_secs_f64());
}use uuid::Uuid;
fn is_valid_uuid(s: &str) -> bool {
Uuid::parse_str(s).is_ok()
}
fn validate_and_parse(s: &str) -> Result<Uuid, String> {
Uuid::parse_str(s).map_err(|e| format!("Invalid UUID: {}", e))
}
fn main() {
let test_cases = vec![
"550e8400-e29b-41d4-a716-446655440000", // Valid
"550e8400e29b41d4a716446655440000", // Valid (simple)
"urn:uuid:550e8400-e29b-41d4-a716-446655440000", // Valid (URN)
"invalid-uuid", // Invalid
"550e8400-e29b-41d4-a716", // Invalid (too short)
"550e8400-e29b-41d4-a716-446655440000ZZ", // Invalid (extra chars)
];
println!("UUID Validation:");
for test in test_cases {
match validate_and_parse(test) {
Ok(uuid) => println!(" Valid: {}", uuid),
Err(e) => println!(" Invalid '{}': {}", test, e),
}
}
}use uuid::Uuid;
use std::collections::HashMap;
use std::time::{Duration, Instant};
#[derive(Clone)]
struct Session {
id: Uuid,
user_id: Uuid,
created_at: Instant,
expires_after: Duration,
data: HashMap<String, String>,
}
impl Session {
fn new(user_id: Uuid, ttl: Duration) -> Self {
Self {
id: Uuid::new_v4(),
user_id,
created_at: Instant::now(),
expires_after: ttl,
data: HashMap::new(),
}
}
fn is_expired(&self) -> bool {
Instant::now().duration_since(self.created_at) > self.expires_after
}
}
struct SessionManager {
sessions: HashMap<Uuid, Session>,
default_ttl: Duration,
}
impl SessionManager {
fn new() -> Self {
Self {
sessions: HashMap::new(),
default_ttl: Duration::from_secs(3600), // 1 hour
}
}
fn create_session(&mut self, user_id: Uuid) -> Uuid {
let session = Session::new(user_id, self.default_ttl);
let id = session.id;
self.sessions.insert(id, session);
id
}
fn get_session(&mut self, session_id: &Uuid) -> Option<&Session> {
// Clean up expired sessions
self.sessions.retain(|_, s| !s.is_expired());
self.sessions.get(session_id)
}
fn get_session_mut(&mut self, session_id: &Uuid) -> Option<&mut Session> {
self.sessions.retain(|_, s| !s.is_expired());
self.sessions.get_mut(session_id)
}
fn destroy_session(&mut self, session_id: &Uuid) -> bool {
self.sessions.remove(session_id).is_some()
}
fn cleanup_expired(&mut self) -> usize {
let before = self.sessions.len();
self.sessions.retain(|_, s| !s.is_expired());
before - self.sessions.len()
}
}
fn main() {
let mut manager = SessionManager::new();
// Create user ID
let user_id = Uuid::new_v4();
println!("User ID: {}", user_id);
// Create session
let session_id = manager.create_session(user_id);
println!("Session ID: {}", session_id);
// Access session
if let Some(session) = manager.get_session(&session_id) {
println!("Session valid for user: {}", session.user_id);
}
// Set session data
if let Some(session) = manager.get_session_mut(&session_id) {
session.data.insert("theme".to_string(), "dark".to_string());
session.data.insert("language".to_string(), "en".to_string());
}
// Get session data
if let Some(session) = manager.get_session(&session_id) {
println!("Theme: {:?}", session.data.get("theme"));
}
// Destroy session
manager.destroy_session(&session_id);
println!("Session destroyed");
if manager.get_session(&session_id).is_none() {
println!("Session no longer exists");
}
}use uuid::Uuid;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone)]
struct Event {
id: Uuid,
event_type: String,
timestamp: u64,
payload: String,
}
impl Event {
fn new(event_type: &str, payload: String) -> Self {
Self {
id: Uuid::new_v4(),
event_type: event_type.to_string(),
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
payload,
}
}
}
struct EventBus {
events: Vec<Event>,
subscribers: Vec<Box<dyn Fn(&Event)>>,
}
impl EventBus {
fn new() -> Self {
Self {
events: Vec::new(),
subscribers: Vec::new(),
}
}
fn subscribe<F: Fn(&Event) + 'static>(&mut self, handler: F) {
self.subscribers.push(Box::new(handler));
}
fn publish(&mut self, event_type: &str, payload: String) -> Uuid {
let event = Event::new(event_type, payload);
let id = event.id;
// Notify subscribers
for handler in &self.subscribers {
handler(&event);
}
self.events.push(event);
id
}
fn get_event(&self, id: &Uuid) -> Option<&Event> {
self.events.iter().find(|e| e.id == *id)
}
fn events_by_type(&self, event_type: &str) -> Vec<&Event> {
self.events.iter()
.filter(|e| e.event_type == event_type)
.collect()
}
}
fn main() {
let mut bus = EventBus::new();
// Subscribe to events
bus.subscribe(|event| {
println!("[Logger] Event {}: {}", event.id, event.event_type);
});
bus.subscribe(|event| {
if event.event_type == "user.created" {
println!("[Welcome] Sending welcome email for event {}", event.id);
}
});
// Publish events
let id1 = bus.publish("user.created", "{\"user_id\": \"alice\"}".to_string());
println!("Created event: {}", id1);
let id2 = bus.publish("user.login", "{\"user_id\": \"alice\"}".to_string());
println!("Created event: {}", id2);
// Retrieve event
if let Some(event) = bus.get_event(&id1) {
println!("\nRetrieved event: {:?}", event);
}
}use uuid::Uuid;
use std::fmt;
#[derive(Debug)]
enum UuidError {
InvalidFormat(String),
InvalidVersion(String),
}
impl fmt::Display for UuidError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UuidError::InvalidFormat(s) => write!(f, "Invalid UUID format: {}", s),
UuidError::InvalidVersion(s) => write!(f, "Invalid UUID version: {}", s),
}
}
}
impl std::error::Error for UuidError {}
fn parse_user_uuid(s: &str) -> Result<Uuid, UuidError> {
let uuid = Uuid::parse_str(s)
.map_err(|e| UuidError::InvalidFormat(e.to_string()))?;
// Validate it's a v4 UUID
match uuid.get_version() {
Some(uuid::Version::Random) => Ok(uuid),
_ => Err(UuidError::InvalidVersion("Expected v4 UUID".to_string())),
}
}
fn main() {
// Valid v4 UUID
let v4_string = Uuid::new_v4().to_string();
match parse_user_uuid(&v4_string) {
Ok(uuid) => println!("Valid v4 UUID: {}", uuid),
Err(e) => println!("Error: {}", e),
}
// Valid but not v4
let v5_string = Uuid::new_v5(Uuid::NAMESPACE_DNS, b"test").to_string();
match parse_user_uuid(&v5_string) {
Ok(uuid) => println!("Valid v4 UUID: {}", uuid),
Err(e) => println!("Error: {}", e),
}
// Invalid format
match parse_user_uuid("not-a-uuid") {
Ok(uuid) => println!("Valid v4 UUID: {}", uuid),
Err(e) => println!("Error: {}", e),
}
}Uuid::new_v4() generates a random UUID (most common, requires v4 feature)Uuid::new_v5(namespace, name) creates deterministic name-based UUIDs (requires v5 feature)Uuid::parse_str(s) parses UUID from string (accepts hyphenated, simple, URN, braced formats)uuid.to_string() returns hyphenated format; uuid.simple() removes hyphensuuid.as_bytes() returns the 16-byte array representationuuid.get_version() returns the UUID version (Random, Mac, Md5, Sha1, etc.)Uuid::nil() returns the nil UUID (all zeros)serde feature for automatic JSON serializationv7 feature)NAMESPACE_DNS, NAMESPACE_URL, NAMESPACE_OID, NAMESPACE_X500