#[derive(Debug, Clone, PartialEq)]
pub(crate) struct ColorNameEntry {
pub base: &'static str,
pub ish: &'static str,
}
impl ColorNameEntry {
const fn new(base: &'static str, ish: &'static str) -> Self {
Self { base, ish }
}
}
pub(crate) const COLOR_NAMES: &[ColorNameEntry] = &[
ColorNameEntry::new("red", "reddish"),
ColorNameEntry::new("blue", "bluish"),
ColorNameEntry::new("green", "greenish"),
ColorNameEntry::new("yellow", "yellowish"),
ColorNameEntry::new("brown", "brownish"),
ColorNameEntry::new("purple", "purplish"),
ColorNameEntry::new("pink", "pinkish"),
ColorNameEntry::new("orange", "orangish"),
ColorNameEntry::new("olive", "olive"), ColorNameEntry::new("violet", "violetish"),
ColorNameEntry::new("gray", "grayish"),
ColorNameEntry::new("grey", "greyish"), ColorNameEntry::new("white", "whitish"),
ColorNameEntry::new("black", "blackish"),
ColorNameEntry::new("yellowish pink", "yellowish pinkish"),
ColorNameEntry::new("reddish orange", "reddish orangish"),
ColorNameEntry::new("reddish brown", "reddish brownish"),
ColorNameEntry::new("orange yellow", "orange yellowish"),
ColorNameEntry::new("yellowish brown", "yellowish brownish"),
ColorNameEntry::new("olive brown", "olive brownish"),
ColorNameEntry::new("greenish yellow", "greenish yellowish"),
ColorNameEntry::new("yellow green", "yellow greenish"),
ColorNameEntry::new("olive green", "olive greenish"),
ColorNameEntry::new("yellowish green", "yellowish greenish"),
ColorNameEntry::new("bluish green", "bluish greenish"),
ColorNameEntry::new("greenish blue", "greenish bluish"),
ColorNameEntry::new("purplish blue", "purplish bluish"),
ColorNameEntry::new("reddish purple", "reddish purplish"),
ColorNameEntry::new("purplish pink", "purplish pinkish"),
ColorNameEntry::new("purplish red", "purplish reddish"),
ColorNameEntry::new("lime", "limish"),
ColorNameEntry::new("teal", "tealish"),
ColorNameEntry::new("turquoise", "turquoisish"),
ColorNameEntry::new("aqua", "aquaish"),
ColorNameEntry::new("beige", "beigeish"),
ColorNameEntry::new("coral", "coralish"),
ColorNameEntry::new("fuchsia", "fuchsiaish"),
ColorNameEntry::new("gold", "goldish"),
ColorNameEntry::new("lavender", "lavenderish"),
ColorNameEntry::new("lilac", "lilacish"),
ColorNameEntry::new("magenta", "magentaish"),
ColorNameEntry::new("mauve", "mauvish"),
ColorNameEntry::new("navy", "navyish"),
ColorNameEntry::new("peach", "peachish"),
ColorNameEntry::new("rose", "roseish"),
ColorNameEntry::new("rust", "rustish"),
ColorNameEntry::new("sand", "sandish"),
ColorNameEntry::new("tan", "tannish"),
ColorNameEntry::new("taupe", "taupish"),
ColorNameEntry::new("wine", "winish"),
];
pub(crate) fn get_ish_form(color_name: &str) -> &str {
COLOR_NAMES
.iter()
.find(|e| e.base == color_name)
.map(|e| e.ish)
.unwrap_or(color_name) }
#[allow(dead_code)]
pub(crate) fn get_base_form(ish_name: &str) -> Option<&'static str> {
COLOR_NAMES
.iter()
.find(|e| e.ish == ish_name)
.map(|e| e.base)
}
pub fn known_color_names() -> impl Iterator<Item = &'static str> {
COLOR_NAMES.iter().map(|e| e.base)
}
pub fn is_known_color(name: &str) -> bool {
COLOR_NAMES.iter().any(|e| e.base == name)
}
pub fn color_name_count() -> usize {
COLOR_NAMES.len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_ish_mappings() {
assert_eq!(get_ish_form("red"), "reddish");
assert_eq!(get_ish_form("blue"), "bluish");
assert_eq!(get_ish_form("green"), "greenish");
assert_eq!(get_ish_form("yellow"), "yellowish");
assert_eq!(get_ish_form("purple"), "purplish");
assert_eq!(get_ish_form("pink"), "pinkish");
assert_eq!(get_ish_form("brown"), "brownish");
}
#[test]
fn test_olive_exception() {
assert_eq!(get_ish_form("olive"), "olive");
}
#[test]
fn test_gray_variants() {
assert_eq!(get_ish_form("gray"), "grayish");
assert_eq!(get_ish_form("grey"), "greyish");
}
#[test]
fn test_semantic_colors() {
assert_eq!(get_ish_form("coral"), "coralish");
assert_eq!(get_ish_form("navy"), "navyish");
assert_eq!(get_ish_form("rust"), "rustish");
assert_eq!(get_ish_form("tan"), "tannish");
assert_eq!(get_ish_form("mauve"), "mauvish");
}
#[test]
fn test_compound_colors() {
assert_eq!(get_ish_form("yellowish pink"), "yellowish pinkish");
assert_eq!(get_ish_form("reddish brown"), "reddish brownish");
assert_eq!(get_ish_form("bluish green"), "bluish greenish");
}
#[test]
fn test_unknown_color_fallback() {
assert_eq!(get_ish_form("unknown"), "unknown");
assert_eq!(get_ish_form("imaginary"), "imaginary");
}
#[test]
fn test_reverse_lookup() {
assert_eq!(get_base_form("reddish"), Some("red"));
assert_eq!(get_base_form("bluish"), Some("blue"));
assert_eq!(get_base_form("olive"), Some("olive"));
assert_eq!(get_base_form("unknown"), None);
}
#[test]
fn test_known_color_names() {
let names: Vec<_> = known_color_names().collect();
assert!(names.contains(&"red"));
assert!(names.contains(&"coral"));
assert!(names.contains(&"lime"));
assert!(names.contains(&"yellowish pink"));
}
#[test]
fn test_is_known_color() {
assert!(is_known_color("red"));
assert!(is_known_color("coral"));
assert!(is_known_color("olive"));
assert!(!is_known_color("unknown"));
assert!(!is_known_color(""));
}
#[test]
fn test_color_count() {
assert!(color_name_count() >= 50);
}
#[test]
fn test_no_duplicate_base_names() {
let names: Vec<_> = known_color_names().collect();
let unique: std::collections::HashSet<_> = names.iter().collect();
assert_eq!(names.len(), unique.len(), "Duplicate base names found");
}
}