1use std::collections::BTreeMap;
4use std::path::PathBuf;
5
6use crate::BackendError;
7
8pub use vyre_foundation::operation::TargetId as AotTargetId;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct LauncherDependency {
14 pub name: &'static str,
16 pub spec: &'static str,
18}
19
20#[derive(Debug)]
22pub struct AotLauncherRequest<'a> {
23 pub target: AotTargetId,
25 pub crate_name: &'a str,
27 pub include_collectives: bool,
29 pub include_ttt_loop: bool,
31}
32
33#[derive(Debug, Clone, Default)]
35pub struct AotLauncherFiles {
36 pub dependencies: Vec<LauncherDependency>,
38 pub files: BTreeMap<PathBuf, String>,
40}
41
42impl AotLauncherFiles {
43 #[must_use]
49 pub fn from_entries(
50 dependencies: Vec<LauncherDependency>,
51 entries: impl IntoIterator<Item = (PathBuf, String)>,
52 ) -> Self {
53 Self {
54 dependencies,
55 files: entries.into_iter().collect(),
56 }
57 }
58}
59
60pub struct AotLauncherEmitter {
62 pub target: AotTargetId,
64 pub emit: fn(&AotLauncherRequest<'_>) -> Result<AotLauncherFiles, String>,
66}
67
68inventory::collect!(AotLauncherEmitter);
69
70#[must_use]
72pub fn registered_aot_launcher_emitters() -> Vec<&'static AotLauncherEmitter> {
73 let emitter_count = inventory::iter::<AotLauncherEmitter>.into_iter().count();
74 let mut emitters = Vec::new();
75 let _ = emitters.try_reserve_exact(emitter_count);
76 emitters.extend(inventory::iter::<AotLauncherEmitter>);
77 emitters
78}
79
80pub fn emit_aot_launcher_target(
88 target: &AotTargetId,
89 request: &AotLauncherRequest<'_>,
90) -> Result<AotLauncherFiles, BackendError> {
91 let Some(emitter) = inventory::iter::<AotLauncherEmitter>
92 .into_iter()
93 .find(|emitter| &emitter.target == target)
94 else {
95 return Err(BackendError::UnsupportedFeature {
96 name: format!("aot launcher target `{target}`"),
97 backend: "vyre-driver".to_string(),
98 });
99 };
100 (emitter.emit)(request).map_err(|compiler_message| BackendError::KernelCompileFailed {
101 backend: target.to_string(),
102 compiler_message,
103 })
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn launcher_files_constructor_centralizes_path_keyed_container_assembly() {
112 let files = AotLauncherFiles::from_entries(
113 vec![LauncherDependency {
114 name: "libc",
115 spec: "\"0.2\"",
116 }],
117 [
118 (PathBuf::from("src/main.rs"), String::from("fn main() {}")),
119 (PathBuf::from("src/cuda_ffi.rs"), String::from("mod ffi {}")),
120 ],
121 );
122
123 assert_eq!(files.dependencies.len(), 1);
124 assert_eq!(files.files.len(), 2);
125 assert_eq!(
126 files.files[&PathBuf::from("src/main.rs")],
127 "fn main() {}",
128 "Fix: launcher file construction must preserve emitted file contents while centralizing the map-shaped public API."
129 );
130 }
131}