use once_cell::sync::Lazy;
use proc_macro2::TokenStream;
use quote::quote;
use std::collections::HashMap;
use std::sync::Mutex;
static COMPILE_TIME_TASK_REGISTRY: Lazy<Mutex<CompileTimeTaskRegistry>> =
Lazy::new(|| Mutex::new(CompileTimeTaskRegistry::new()));
#[derive(Debug, Clone)]
pub struct TaskInfo {
pub id: String,
pub dependencies: Vec<String>,
pub file_path: String,
}
#[derive(Debug)]
pub struct CompileTimeTaskRegistry {
tasks: HashMap<String, TaskInfo>,
dependency_graph: HashMap<String, Vec<String>>,
}
impl CompileTimeTaskRegistry {
pub fn new() -> Self {
Self {
tasks: HashMap::new(),
dependency_graph: HashMap::new(),
}
}
pub fn register_task(&mut self, task_info: TaskInfo) -> Result<(), CompileTimeError> {
let task_id = &task_info.id;
if let Some(existing) = self.tasks.get(task_id) {
return Err(CompileTimeError::DuplicateTaskId {
task_id: task_id.clone(),
existing_location: existing.file_path.clone(),
duplicate_location: task_info.file_path.clone(),
});
}
self.dependency_graph
.insert(task_id.clone(), task_info.dependencies.clone());
self.tasks.insert(task_id.clone(), task_info);
Ok(())
}
pub fn get_all_task_ids(&self) -> Vec<String> {
self.tasks.keys().cloned().collect()
}
}
#[derive(Debug)]
pub enum CompileTimeError {
DuplicateTaskId {
task_id: String,
existing_location: String,
duplicate_location: String,
},
}
impl CompileTimeError {
pub fn to_compile_error(&self) -> TokenStream {
let CompileTimeError::DuplicateTaskId {
task_id,
existing_location,
duplicate_location,
} = self;
let msg = format!(
"Duplicate task ID '{}'. Already defined at '{}', redefined at '{}'",
task_id, existing_location, duplicate_location
);
quote! { compile_error!(#msg); }
}
}
pub fn get_registry() -> &'static Lazy<Mutex<CompileTimeTaskRegistry>> {
&COMPILE_TIME_TASK_REGISTRY
}