cronspeak 0.1.1

Convert cron expressions into clear, human-readable English descriptions (like cronstrue / cron-descriptor). Zero-dependency, no_std.
Documentation
//! Naming helpers: clock times, month/day names, and list joining.

use alloc::format;
use alloc::string::String;

use crate::TimeFormat;

const MONTHS: [&str; 12] = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
];

const DAYS: [&str; 7] = [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
];

/// Month name for `1..=12`; falls back to the number if out of range.
pub(crate) fn month_name(m: u32) -> String {
    MONTHS
        .get((m as usize).wrapping_sub(1))
        .map_or_else(|| format!("month {m}"), |s| String::from(*s))
}

/// Day-of-week name for `0..=7` (0 and 7 both = Sunday).
pub(crate) fn day_name(w: u32) -> String {
    DAYS.get((w % 7) as usize)
        .map_or_else(|| format!("day {w}"), |s| String::from(*s))
}

/// Render a clock time in the requested [`TimeFormat`].
pub(crate) fn clock(hour: u32, minute: u32, fmt: TimeFormat) -> String {
    match fmt {
        TimeFormat::H24 => format!("{hour:02}:{minute:02}"),
        TimeFormat::H12 => {
            let period = if hour < 12 { "AM" } else { "PM" };
            let h12 = match hour % 12 {
                0 => 12,
                h => h,
            };
            format!("{h12:02}:{minute:02} {period}")
        }
    }
}

/// Join items in English: `"a"`, `"a and b"`, `"a, b and c"`.
pub(crate) fn human_list(items: &[String]) -> String {
    match items {
        [] => String::new(),
        [one] => one.clone(),
        [a, b] => format!("{a} and {b}"),
        [rest @ .., last] => format!("{} and {last}", rest.join(", ")),
    }
}

/// Capitalize the first character of `s`.
pub(crate) fn capitalize(s: &str) -> String {
    let mut chars = s.chars();
    match chars.next() {
        None => String::new(),
        Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
    }
}