uuinfo 0.6.8

A tool to debug unique identifiers (UUID, ULID, Snowflake, etc).
use basen::BASE36;

use crate::schema::{Args, IDInfo};
use crate::utils::{factor_size_hex_bits_color_from_text, milliseconds_to_seconds_and_iso8601};

pub fn parse_puid(args: &Args) -> Option<IDInfo> {
    if args.id.chars().count() != 24 {
        return None;
    }
    let timestamp_raw: u64 = BASE36.decode_var_len(&args.id[0..8])?;
    let _ = hex::decode(&args.id[8..14]).ok()?;
    let process_id: u64 = BASE36.decode_var_len(&args.id[14..18])?;
    let sequence: u64 = BASE36.decode_var_len(&args.id[18..24])?;
    let machine_id = &args.id[8..14];
    let (size, hex, bits, _) = factor_size_hex_bits_color_from_text(&args.id);
    let (timestamp, datetime) = milliseconds_to_seconds_and_iso8601(timestamp_raw, None);

    Some(IDInfo {
        id_type: "Puid".to_string(),
        standard: args.id.clone(),
        parsed: Some("as ASCII, with base36 parts".to_string()),
        size,
        datetime: Some(datetime),
        timestamp: Some(timestamp.to_string()),
        node1: Some(format!("{} (Machine ID)", machine_id)),
        node2: Some(format!("{} (Process ID)", process_id)),
        sequence: Some(sequence as u128),
        hex,
        bits,
        color_map: Some(format!(
            "{}{}{}{}",
            (0..64).map(|_| "3").collect::<String>(),
            (0..48).map(|_| "4").collect::<String>(),
            (0..32).map(|_| "5").collect::<String>(),
            (0..48).map(|_| "6").collect::<String>(),
        )),
        high_confidence: true,
        ..Default::default()
    })
}

pub fn parse_shortpuid(args: &Args) -> Option<IDInfo> {
    match args.id.chars().count() {
        12 | 14 => (),
        _ => return None,
    }
    let timestamp_raw: u64 = BASE36.decode_var_len(&args.id[0..12])?;
    let version: Option<String>;
    let node1: Option<String>;
    let color_map: Option<String>;

    if args.id.chars().count() == 14 {
        let node_id: u64 = BASE36.decode_var_len(&args.id[12..14])?;
        version = Some("Short puid with node ID".to_string());
        node1 = Some(format!("{} (Node ID)", node_id));
        color_map = Some(format!("{}{}", (0..96).map(|_| "3").collect::<String>(), (0..16).map(|_| "4").collect::<String>(),));
    } else {
        version = Some("Short puid without node ID".to_string());
        node1 = None;
        color_map = Some((0..96).map(|_| "3").collect::<String>());
    }
    let (size, hex, bits, _) = factor_size_hex_bits_color_from_text(&args.id);
    let (timestamp, datetime) = milliseconds_to_seconds_and_iso8601(timestamp_raw / 1_000_000, None);

    Some(IDInfo {
        id_type: "Puid".to_string(),
        version,
        standard: args.id.clone(),
        parsed: Some("as ASCII, with base36 parts".to_string()),
        size,
        datetime: Some(datetime),
        timestamp: Some(timestamp.to_string()),
        node1,
        hex,
        bits,
        color_map,
        high_confidence: true,
        ..Default::default()
    })
}

pub fn parse_puid_any(args: &Args) -> Option<IDInfo> {
    match args.id.chars().count() {
        24 => parse_puid(args),
        14 | 12 => parse_shortpuid(args),
        _ => None,
    }
}