o192 0.2.2

ORION-192: ordered, resilient, independent, URL-safe 192-bit IDs for distributed systems.
Documentation
//! Pure parsing utilities for ORION-192 strings.

use crate::codec::{decode_sortable64, read_uint48_be, to_hex};
use crate::error::OrionIdError;

/// Structured view of a parsed ORION-192 identifier.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ParsedOrionId {
    /// The original canonical string.
    pub id: String,
    /// 24-byte binary form.
    pub bytes: [u8; crate::alphabet::ID_SIZE_BYTES],
    /// Absolute Unix milliseconds (`relative_ms + epoch_ms`).
    pub unix_ms: u128,
    /// Milliseconds since the configured `epoch_ms`.
    pub relative_ms: u128,
    /// 12-bit sub-millisecond fraction (`0..4095`).
    pub fraction4096: u16,
    /// 20-bit per-generator monotonic counter.
    pub counter: u32,
    /// Lower-case hex encoding of the 14-byte random tail.
    pub random_hex: String,
}

/// Parse a canonical ORION-192 string.
///
/// # Errors
///
/// Returns the same error variants as [`decode_sortable64`].
pub fn parse(id: &str, epoch_ms: u128) -> Result<ParsedOrionId, OrionIdError> {
    let bytes = decode_sortable64(id)?;
    let relative_ms = read_uint48_be(&bytes, 0);
    let fraction4096 = (u16::from(bytes[6]) << 4) | (u16::from(bytes[7]) >> 4);
    let counter =
        (u32::from(bytes[7] & 0x0f) << 16) | (u32::from(bytes[8]) << 8) | u32::from(bytes[9]);
    let unix_ms = relative_ms.saturating_add(epoch_ms);
    let random_hex = to_hex(&bytes[10..]);

    Ok(ParsedOrionId {
        id: id.to_string(),
        bytes,
        unix_ms,
        relative_ms,
        fraction4096,
        counter,
        random_hex,
    })
}

/// Return `true` if `id` is a syntactically valid canonical ORION-192 string.
pub fn is_valid(id: &str) -> bool {
    decode_sortable64(id).is_ok()
}