use std::collections::BTreeMap;
use std::path::PathBuf;
use crate::{BackendError, DispatchConfig};
use vyre_foundation::ir::Program;
pub type AotTargetId = &'static str;
pub struct AotEmitter {
pub target: AotTargetId,
pub emit: fn(&Program, &DispatchConfig) -> Result<Vec<u8>, String>,
}
inventory::collect!(AotEmitter);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LauncherDependency {
pub name: &'static str,
pub spec: &'static str,
}
#[derive(Debug)]
pub struct AotLauncherRequest<'a> {
pub target: AotTargetId,
pub crate_name: &'a str,
pub include_collectives: bool,
pub include_ttt_loop: bool,
}
#[derive(Debug, Clone, Default)]
pub struct AotLauncherFiles {
pub dependencies: Vec<LauncherDependency>,
pub files: BTreeMap<PathBuf, String>,
}
impl AotLauncherFiles {
#[must_use]
pub fn from_entries(
dependencies: Vec<LauncherDependency>,
entries: impl IntoIterator<Item = (PathBuf, String)>,
) -> Self {
Self {
dependencies,
files: entries.into_iter().collect(),
}
}
}
pub struct AotLauncherEmitter {
pub target: AotTargetId,
pub emit: fn(&AotLauncherRequest<'_>) -> Result<AotLauncherFiles, String>,
}
inventory::collect!(AotLauncherEmitter);
#[must_use]
pub fn registered_aot_emitters() -> Vec<&'static AotEmitter> {
let emitter_count = inventory::iter::<AotEmitter>.into_iter().count();
let mut emitters = Vec::new();
emitters.try_reserve_exact(emitter_count).unwrap_or_else(|error| {
panic!(
"Vyre AOT emitter inventory could not reserve {emitter_count} emitter slot(s): {error}. Fix: reduce linked AOT emitter inventory or split registry initialization."
)
});
emitters.extend(inventory::iter::<AotEmitter>);
emitters
}
#[must_use]
pub fn registered_aot_launcher_emitters() -> Vec<&'static AotLauncherEmitter> {
let emitter_count = inventory::iter::<AotLauncherEmitter>.into_iter().count();
let mut emitters = Vec::new();
emitters.try_reserve_exact(emitter_count).unwrap_or_else(|error| {
panic!(
"Vyre AOT launcher inventory could not reserve {emitter_count} launcher emitter slot(s): {error}. Fix: reduce linked launcher emitter inventory or split registry initialization."
)
});
emitters.extend(inventory::iter::<AotLauncherEmitter>);
emitters
}
pub fn emit_aot_target(
target: &str,
program: &Program,
config: &DispatchConfig,
) -> Result<Vec<u8>, BackendError> {
let Some(emitter) = inventory::iter::<AotEmitter>
.into_iter()
.find(|emitter| emitter.target == target)
else {
return Err(BackendError::UnsupportedFeature {
name: format!("aot target `{target}`"),
backend: "vyre-driver".to_string(),
});
};
(emitter.emit)(program, config).map_err(|compiler_message| BackendError::KernelCompileFailed {
backend: target.to_string(),
compiler_message,
})
}
pub fn emit_aot_launcher_target(
target: &str,
request: &AotLauncherRequest<'_>,
) -> Result<AotLauncherFiles, BackendError> {
let Some(emitter) = inventory::iter::<AotLauncherEmitter>
.into_iter()
.find(|emitter| emitter.target == target)
else {
return Err(BackendError::UnsupportedFeature {
name: format!("aot launcher target `{target}`"),
backend: "vyre-driver".to_string(),
});
};
(emitter.emit)(request).map_err(|compiler_message| BackendError::KernelCompileFailed {
backend: target.to_string(),
compiler_message,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn launcher_files_constructor_centralizes_path_keyed_container_assembly() {
let files = AotLauncherFiles::from_entries(
vec![LauncherDependency {
name: "libc",
spec: "\"0.2\"",
}],
[
(PathBuf::from("src/main.rs"), String::from("fn main() {}")),
(PathBuf::from("src/cuda_ffi.rs"), String::from("mod ffi {}")),
],
);
assert_eq!(files.dependencies.len(), 1);
assert_eq!(files.files.len(), 2);
assert_eq!(
files.files[&PathBuf::from("src/main.rs")],
"fn main() {}",
"Fix: launcher file construction must preserve emitted file contents while centralizing the map-shaped public API."
);
}
}