Skip to content

UUID Generator — Rust source

Generate RFC 4122 v4 UUIDs with crypto-grade randomness. Bulk generate, copy all, toggle format (uppercase / no hyphens).

This is the Rust implementation — the same logic the interactive tool runs, in a shareable, citable form.

//! RFC 4122 v4 UUID generator (cryptographically secure).
//!
//! Language: Rust
//! CosmoDev polyglot showcase port of the `uuid` tool.
//! Ported from src/lib/uuid.ts — display source, part of CosmoDev's
//! polyglot tool pages.
//!
//! Produces a random (v4) UUID: 36 characters, lowercase, hyphenated as
//! 8-4-4-4-12 hex digits, with the RFC version (4) and variant (10xx)
//! bits set.
//!
//! Rust ships no CSPRNG in the standard library, so this port uses the
//! `rand` crate's `ThreadRng` — a user-space CSPRNG (ChaCha12) seeded
//! from the OS entropy source. It is the idiomatic secure choice for
//! unpredictable identifiers. (Cargo.toml: `rand = "0.8"`)

use rand::{thread_rng, RngCore};

/// Lookup table for a single byte -> two lowercase hex characters.
const HEX: &[u8; 16] = b"0123456789abcdef";

/// Generate one RFC 4122 version-4 UUID string.
///
/// Returns `Err` only if the OS entropy source cannot be consulted —
/// the practical equivalent of the TypeScript lib's implicit failure
/// when `crypto` is absent.
pub fn uuid_v4() -> Result<String, std::io::Error> {
    let mut bytes = [0u8; 16];

    // thread_rng() yields a ThreadRng (CSPRNG). try_fill_bytes blocks
    // until the kernel entropy pool is ready and writes the full buffer,
    // surfacing a genuine error if the source is unavailable.
    thread_rng().try_fill_bytes(&mut bytes)?;

    // version 4: high nibble of byte 6 -> 0100
    bytes[6] = (bytes[6] & 0x0f) | 0x40;
    // variant  : high bits of byte 8   -> 10, so the next hex digit is 8-b
    bytes[8] = (bytes[8] & 0x3f) | 0x80;

    // Assemble the canonical 8-4-4-4-12 layout directly into a fixed
    // 36-byte buffer. Hyphens sit at output positions 8, 13, 18, 23;
    // every byte contributes two hex characters.
    let mut out = [0u8; 36];
    let mut o = 0usize;
    for i in 0..16 {
        if i == 4 || i == 6 || i == 8 || i == 10 {
            out[o] = b'-';
            o += 1;
        }
        out[o] = HEX[(bytes[i] >> 4) as usize];
        out[o + 1] = HEX[(bytes[i] & 0x0f) as usize];
        o += 2;
    }

    // Output is plain ASCII hex + dashes, hence always valid UTF-8.
    Ok(String::from_utf8(out.to_vec()).expect("hex output is valid ASCII"))
}

fn main() {
    match uuid_v4() {
        Ok(id) => println!("{id}"),
        Err(e) => eprintln!("error: {e}"),
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →