oxirs 0.2.4

Command-line interface for OxiRS - import, export, migration, and benchmarking tools
Documentation
//! UUID Generator for Blank Nodes
//!
//! Generates UUIDs suitable for use as blank node identifiers in RDF.

use super::ToolResult;

/// Run UUID generation
pub async fn run(count: usize, format: String) -> ToolResult {
    println!("UUID Generator");
    println!("Count: {count}");
    println!("Format: {format}");

    // Validate format
    let supported_formats = ["uuid", "urn", "bnode"];
    if !supported_formats.contains(&format.as_str()) {
        return Err(format!(
            "Unsupported format '{}'. Supported: {}",
            format,
            supported_formats.join(", ")
        )
        .into());
    }

    println!("\nGenerated UUIDs:");
    println!("================");

    for i in 0..count {
        let uuid = generate_uuid();
        let formatted_uuid = format_uuid(&uuid, &format);

        if count > 1 {
            println!("{:3}: {}", i + 1, formatted_uuid);
        } else {
            println!("{formatted_uuid}");
        }
    }

    if count > 1 {
        println!("\nGenerated {count} UUIDs");
    }

    Ok(())
}

/// Generate a UUID v4 (random)
fn generate_uuid() -> String {
    // Simple UUID v4 generation
    // In practice, you'd use the `uuid` crate for proper UUID generation
    use std::time::{SystemTime, UNIX_EPOCH};

    let timestamp = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("SystemTime should be after UNIX_EPOCH")
        .as_nanos();

    let random_part = {
        use scirs2_core::random::Random;
        let mut random = Random::default();
        random.random_range(0..u64::MAX)
    };

    // Create a pseudo-UUID v4 format
    // Real implementation would use proper random bytes and UUID formatting
    format!(
        "{:08x}-{:04x}-4{:03x}-{:04x}-{:08x}{:04x}",
        (timestamp & 0xffffffff) as u32,
        ((timestamp >> 32) & 0xffff) as u16,
        ((timestamp >> 48) & 0xfff) as u16,
        (random_part & 0xffff) as u16,
        ((random_part >> 16) & 0xffffffff) as u32,
        ((random_part >> 48) & 0xffff) as u16,
    )
}

/// Format UUID according to specified format
fn format_uuid(uuid: &str, format: &str) -> String {
    match format {
        "uuid" => uuid.to_string(),
        "urn" => format!("urn:uuid:{uuid}"),
        "bnode" => format!("_:uuid{}", uuid.replace('-', "")),
        _ => uuid.to_string(), // Fallback
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_generate_uuid() {
        let uuid1 = generate_uuid();
        let uuid2 = generate_uuid();

        // UUIDs should be different
        assert_ne!(uuid1, uuid2);

        // Should be proper UUID format
        assert_eq!(uuid1.len(), 36); // 32 hex chars + 4 hyphens
        assert_eq!(uuid1.matches('-').count(), 4);
    }

    #[test]
    fn test_format_uuid() {
        let uuid = "550e8400-e29b-41d4-a716-446655440000";

        assert_eq!(format_uuid(uuid, "uuid"), uuid);
        assert_eq!(
            format_uuid(uuid, "urn"),
            "urn:uuid:550e8400-e29b-41d4-a716-446655440000"
        );
        assert_eq!(
            format_uuid(uuid, "bnode"),
            "_:uuid550e8400e29b41d4a716446655440000"
        );
    }
}