use std::fmt;
pub fn format_display_id(prefix: &str, seq: u32) -> String {
format!("{}-{:04}", prefix, seq)
}
pub fn parse_display_id(id: &str) -> Option<(&str, u32)> {
let dash = id.rfind('-')?;
let prefix = &id[..dash];
let num_str = &id[dash + 1..];
let seq: u32 = num_str.parse().ok()?;
Some((prefix, seq))
}
pub fn validate_task_prefix(prefix: &str) -> Result<(), String> {
if prefix.is_empty() || prefix.len() > 10 {
return Err("Prefix must be 1-10 characters.".into());
}
if !prefix.chars().all(|c| c.is_ascii_uppercase()) {
return Err("Prefix must be uppercase ASCII letters.".into());
}
Ok(())
}
pub type InternalId = ulid::Ulid;
pub fn new_internal_id() -> InternalId {
ulid::Ulid::new()
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TaskId(pub String);
impl fmt::Display for TaskId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProgressId(pub String);
impl fmt::Display for ProgressId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DecisionId(pub String);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HandoffId(pub String);