use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use super::builtin::{CategoryDef, BUILTIN_CATEGORIES, DEFAULT_CATEGORY_PRIORITY};
#[derive(Debug, Clone)]
pub struct CategoryStore {
categories: HashMap<String, CategoryDef>,
}
impl CategoryStore {
pub fn builtin() -> Self {
let categories = BUILTIN_CATEGORIES
.iter()
.map(|b| (b.name.to_string(), CategoryDef::from(b)))
.collect();
Self { categories }
}
pub fn with_config(mut self, config: &CategoriesConfig) -> Self {
for (name, entry) in &config.categories {
self.categories.insert(
name.clone(),
CategoryDef {
name: name.clone(),
description: entry.description.clone(),
patterns: entry.patterns.clone(),
priority: entry.priority.unwrap_or(DEFAULT_CATEGORY_PRIORITY),
},
);
}
self
}
pub fn get(&self, name: &str) -> Option<&CategoryDef> {
self.categories.get(name)
}
pub fn all(&self) -> Vec<&CategoryDef> {
let mut categories: Vec<_> = self.categories.values().collect();
categories.sort_by(|a, b| b.priority.cmp(&a.priority));
categories
}
pub fn names(&self) -> Vec<&str> {
self.categories.keys().map(|s| s.as_str()).collect()
}
}
impl Default for CategoryStore {
fn default() -> Self {
Self::builtin()
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CategoriesConfig {
#[serde(flatten)]
pub categories: HashMap<String, CategoryConfigEntry>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CategoryConfigEntry {
pub description: String,
pub patterns: Vec<String>,
#[serde(default)]
pub priority: Option<i32>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_category_store_builtin() {
let store = CategoryStore::builtin();
assert!(store.get("plan").is_some());
assert!(store.get("execute").is_some());
assert!(store.get("nonexistent").is_none());
}
#[test]
fn test_category_store_override() {
let store = CategoryStore::builtin();
let config = CategoriesConfig {
categories: [(
"plan".to_string(),
CategoryConfigEntry {
description: "Custom plan".to_string(),
patterns: vec!["custom/*".to_string()],
priority: Some(200),
},
)]
.into_iter()
.collect(),
};
let store = store.with_config(&config);
let plan = store.get("plan").unwrap();
assert_eq!(plan.description, "Custom plan");
assert_eq!(plan.priority, 200);
}
}