pub const DATE_FORMAT_PATTERN: &str = "YYYY-MM-DD";
pub const STRIKE_PRICE_DECIMALS: usize = 4;
pub fn parse_date(value: &str) -> Result<String, String> {
let bytes = value.as_bytes();
let shaped = bytes.len() == 10
&& bytes[4] == b'-'
&& bytes[7] == b'-'
&& value
.char_indices()
.all(|(i, c)| i == 4 || i == 7 || c.is_ascii_digit());
if !shaped {
return Err(format!("must be in {DATE_FORMAT_PATTERN} format"));
}
let month: u8 = value[5..7]
.parse()
.map_err(|_| "invalid month".to_string())?;
let day: u8 = value[8..10]
.parse()
.map_err(|_| "invalid day".to_string())?;
if !(1..=12).contains(&month) || !(1..=31).contains(&day) {
return Err(format!(
"must be a real calendar date in {DATE_FORMAT_PATTERN} format"
));
}
Ok(value.to_string())
}
pub fn parse_uuid(value: &str) -> Result<String, String> {
let groups: Vec<&str> = value.split('-').collect();
let lengths_ok = groups.len() == 5
&& [8usize, 4, 4, 4, 12]
.iter()
.zip(&groups)
.all(|(want, g)| g.len() == *want);
let hex_ok = groups
.iter()
.all(|g| g.chars().all(|c| c.is_ascii_hexdigit()));
if lengths_ok && hex_ok {
Ok(value.to_string())
} else {
Err("must be a valid UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)".to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_date_accepts_valid() {
assert_eq!(parse_date("2026-06-01").unwrap(), "2026-06-01");
}
#[test]
fn parse_date_rejects_garbage() {
assert!(parse_date("not-a-date").is_err());
assert!(parse_date("2026/06/01").is_err());
assert!(parse_date("2026-13-40").is_err());
assert!(parse_date("206-6-1").is_err());
}
#[test]
fn parse_uuid_accepts_valid() {
let id = "6a1b9bec-419a-4bab-97bc-c1f562be70c4";
assert_eq!(parse_uuid(id).unwrap(), id);
}
#[test]
fn parse_uuid_rejects_garbage() {
assert!(parse_uuid("not-a-uuid").is_err());
assert!(parse_uuid("6a1b9bec419a4bab97bcc1f562be70c4").is_err());
}
}