vyre_driver/
materialize.rs1use std::collections::{BTreeMap, BTreeSet};
16use std::sync::Arc;
17
18use vyre_foundation::ir::Program;
19use vyre_megakernel::{
20 Artifact, ArtifactValueId, FusionRecord, ResourceLifetime, TargetModuleBundle,
21 TargetModuleImage, TargetPayload, TargetPayloadFormat, TargetProfile,
22};
23
24use crate::{BackendError, DispatchConfig};
25
26#[must_use]
28pub fn invalid_module(reason: &str) -> BackendError {
29 BackendError::InvalidProgram {
30 fix: format!("Fix: {reason}. Recompile the target payload from the neutral artifact."),
31 }
32}
33
34#[must_use]
36pub fn compile_error(backend: &str, error: impl std::fmt::Display) -> BackendError {
37 BackendError::KernelCompileFailed {
38 backend: backend.to_string(),
39 compiler_message: format!(
40 "{error}. Fix: rebuild the target payload from the neutral artifact."
41 ),
42 }
43}
44
45#[derive(Clone, Copy, Debug)]
47pub struct MaterializerTarget<'a> {
48 pub backend_id: &'a str,
50 pub format: &'a TargetPayloadFormat,
52 pub profile: &'a TargetProfile,
54}
55
56#[derive(Debug)]
58pub struct AdmittedModule {
59 pub image: TargetModuleImage,
61 pub program: Arc<Program>,
63 pub config: DispatchConfig,
65}
66
67pub fn admit(
82 artifact: &Artifact,
83 payload: &TargetPayload,
84 target: MaterializerTarget<'_>,
85) -> Result<Vec<AdmittedModule>, BackendError> {
86 if payload.neutral_artifact() != artifact.digest() {
87 return Err(invalid_module(
88 "target payload is not authenticated for the supplied neutral artifact",
89 ));
90 }
91 if payload.format() != target.format {
92 return Err(BackendError::UnsupportedFeature {
93 name: format!("target payload format `{}`", payload.format().identity()),
94 backend: target.backend_id.to_string(),
95 });
96 }
97 if payload.profile() != target.profile {
98 return Err(invalid_module(
99 "target payload profile does not match the acquired materializer profile",
100 ));
101 }
102
103 let bundle = TargetModuleBundle::from_bytes(payload.bytes())
104 .map_err(|error| compile_error(target.backend_id, error))?;
105 let selected = artifact.fusion();
106 if bundle.modules.len() != selected.len() {
107 return Err(invalid_module(
108 "target module count must equal the compiler-selected fusion-group count",
109 ));
110 }
111 if payload.entries().len() != selected.len() {
112 return Err(invalid_module(
113 "target entry count must equal the compiler-selected fusion-group count",
114 ));
115 }
116
117 let mut admitted = Vec::with_capacity(selected.len());
118 for ((image, record), entry) in bundle
119 .modules
120 .into_iter()
121 .zip(selected)
122 .zip(payload.entries())
123 {
124 admit_module_identity(&image, record)?;
125 if image.entry_point != "main" {
126 return Err(invalid_module("target module entry point must be `main`"));
127 }
128 if entry.name != image.entry_point {
129 return Err(invalid_module(
130 "target entry metadata must name the emitted target entry point",
131 ));
132 }
133 let program = Arc::new(Program::from_wire(&image.program).map_err(|error| {
134 invalid_module(&format!("selected Program is malformed: {error}"))
135 })?);
136 let mut config = DispatchConfig::default();
137 config.grid_override = Some(entry.grid_size);
138 config.dispatch_grid = Some(entry.grid_size);
139 admitted.push(AdmittedModule {
140 image,
141 program,
142 config,
143 });
144 }
145 Ok(admitted)
146}
147
148fn admit_module_identity(
150 image: &TargetModuleImage,
151 record: &FusionRecord,
152) -> Result<(), BackendError> {
153 if image.group != record.id || image.stage != record.stage || image.nodes != record.members {
154 return Err(invalid_module(
155 "target module group/stage/node identity must match the neutral selected plan",
156 ));
157 }
158 Ok(())
159}
160
161pub struct ResourceProjection {
163 pub values: BTreeMap<String, ArtifactValueId>,
165 pub outputs: BTreeSet<ArtifactValueId>,
167 pub retained: BTreeSet<ArtifactValueId>,
169}
170
171#[must_use]
176pub fn project_resources(artifact: &Artifact) -> ResourceProjection {
177 let mut projection = ResourceProjection {
178 values: BTreeMap::new(),
179 outputs: BTreeSet::new(),
180 retained: BTreeSet::new(),
181 };
182 for resource in artifact.resources() {
183 projection
184 .values
185 .insert(resource.name.clone(), resource.value);
186 match resource.lifetime {
187 ResourceLifetime::Output => {
188 projection.outputs.insert(resource.value);
189 }
190 ResourceLifetime::Retained => {
191 projection.retained.insert(resource.value);
192 }
193 _ => {}
194 }
195 }
196 projection
197}