use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
use sha2::{Digest, Sha256};
use time::macros::format_description;
use time::OffsetDateTime;
static COUNTER: AtomicU64 = AtomicU64::new(0);
pub fn unique() -> String {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or_default();
let count = COUNTER.fetch_add(1, Ordering::Relaxed);
format!("{:x}-{nanos:x}-{count:x}", std::process::id())
}
pub fn session_token() -> String {
format!("s-{}", short_digest(&unique()))
}
pub fn artifact_id() -> String {
format!("a-{}", short_digest(&unique()))
}
pub fn is_safe_name(value: &str) -> bool {
!value.is_empty()
&& value != "."
&& value != ".."
&& value
.chars()
.all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))
}
pub fn short_digest(value: &str) -> String {
digest(value)[..12].to_owned()
}
pub fn digest(value: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(value.as_bytes());
hasher
.finalize()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
pub fn timestamp() -> String {
let description =
format_description!("[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z");
OffsetDateTime::now_utc()
.format(description)
.unwrap_or_else(|_| "1970-01-01T00:00:00.000Z".to_owned())
}