vyre_driver/backend/registry/
inventory_streams.rs1use std::collections::HashSet;
4use std::sync::{Arc, LazyLock};
5
6use vyre_foundation::ir::OpId;
7use vyre_foundation::operation::{TargetId, TargetOperationFacet};
8
9use super::grid_sync_split::wrap_grid_sync_split;
10use crate::backend::{ArtifactMaterializer, BackendError, VyreBackend};
11use vyre_megakernel::TargetCompiler;
12
13struct RegisteredOperationSupport {
14 id: &'static str,
15 operations: &'static HashSet<OpId>,
16}
17
18impl crate::backend::Backend for RegisteredOperationSupport {
19 fn id(&self) -> &'static str {
20 self.id
21 }
22
23 fn version(&self) -> &'static str {
24 "registered-target-compiler"
25 }
26
27 fn supported_ops(&self) -> &HashSet<OpId> {
28 self.operations
29 }
30}
31
32#[derive(Clone)]
39pub struct BackendRegistration {
40 pub id: &'static str,
42 pub target_id: TargetId,
44 pub payload_format: Option<&'static str>,
48 pub reference_oracle: bool,
51 pub factory: fn() -> Result<Box<dyn VyreBackend>, BackendError>,
57 pub supported_ops: fn() -> &'static HashSet<OpId>,
59 pub semantic_operations: fn() -> &'static HashSet<OpId>,
65 pub target_compiler: Option<fn() -> Result<Box<dyn TargetCompiler>, BackendError>>,
67 pub materializer: Option<fn() -> Result<Box<dyn ArtifactMaterializer>, BackendError>>,
69}
70
71impl BackendRegistration {
72 pub fn acquire(&self) -> Result<Box<dyn VyreBackend>, BackendError> {
83 (self.factory)().map(wrap_grid_sync_split)
84 }
85
86 pub fn target_compiler(&self) -> Result<Box<dyn TargetCompiler>, BackendError> {
94 let factory = self
95 .target_compiler
96 .ok_or_else(|| BackendError::UnsupportedFeature {
97 name: "registered target compiler; Fix: link a backend crate that registers native artifact compilation instead of passing a raw Program".to_string(),
98 backend: self.id.to_string(),
99 })?;
100 let expected = self.payload_format.ok_or_else(|| {
101 BackendError::new(format!(
102 "backend `{}` registers a target compiler without a payload format. Fix: declare the concrete owner-local payload format in BackendRegistration.",
103 self.id
104 ))
105 })?;
106 let compiler = factory()?;
107 if compiler.format().identity() != expected {
108 return Err(BackendError::new(format!(
109 "backend `{}` registers payload format `{expected}` but constructed compiler format `{}`. Fix: keep the concrete target registration and compiler format identical.",
110 self.id,
111 compiler.format().identity()
112 )));
113 }
114 Ok(compiler)
115 }
116
117 pub fn materializer(&self) -> Result<Box<dyn ArtifactMaterializer>, BackendError> {
124 self.materializer
125 .ok_or_else(|| BackendError::UnsupportedFeature {
126 name: "registered artifact materializer; Fix: link the backend's native materializer instead of recompiling a raw Program at dispatch".to_string(),
127 backend: self.id.to_string(),
128 })?()
129 }
130}
131
132inventory::collect!(BackendRegistration);
133
134pub fn registered_target_operation_facets() -> Result<&'static [TargetOperationFacet], BackendError>
144{
145 static FACETS: LazyLock<Result<Arc<[TargetOperationFacet]>, BackendError>> = LazyLock::new(
146 || {
147 let backends = registered_backends()?;
148 let mut facets = Vec::new();
149 let facet_count = backends.iter().fold(0usize, |count, backend| {
150 count.saturating_add((backend.semantic_operations)().len())
151 });
152 crate::allocation::reserve_vec_to_capacity(
153 &mut facets,
154 facet_count,
155 "Vyre target facet registry",
156 "target operation facet",
157 "reduce linked target operation declarations",
158 )?;
159 for backend in backends
160 .iter()
161 .filter(|backend| backend.target_compiler.is_some())
162 {
163 for operation_id in (backend.semantic_operations)() {
164 let operation =
165 vyre_foundation::operation::OperationRegistry::global()
166 .get(operation_id)
167 .ok_or_else(|| {
168 BackendError::new(format!(
169 "target `{}` advertises unknown semantic operation `{operation_id}`. Fix: submit one canonical OperationRegistration or remove the stale target facet.",
170 backend.target_id
171 ))
172 })?;
173 if operation.program().is_some() {
174 facets.push(TargetOperationFacet {
175 operation_id: operation.id,
176 target_id: backend.target_id.clone(),
177 version: 1,
178 });
179 }
180 }
181 }
182 facets.sort_unstable_by(|left, right| {
183 (left.operation_id, &left.target_id).cmp(&(right.operation_id, &right.target_id))
184 });
185 for pair in facets.windows(2) {
186 if pair[0].operation_id == pair[1].operation_id
187 && pair[0].target_id == pair[1].target_id
188 {
189 return Err(BackendError::new(format!(
190 "duplicate target facet for operation `{}` and target `{}`. Fix: keep one concrete-driver semantic operation declaration per target.",
191 pair[0].operation_id, pair[0].target_id
192 )));
193 }
194 }
195 Ok(Arc::from(facets))
196 },
197 );
198 match &*FACETS {
199 Ok(facets) => Ok(facets.as_ref()),
200 Err(error) => Err(error.clone()),
201 }
202}
203
204pub struct BackendPrecedence {
210 pub id: &'static str,
213 pub rank: u32,
215}
216
217inventory::collect!(BackendPrecedence);
218
219pub struct BackendCapability {
222 pub id: &'static str,
225 pub dispatches: bool,
228}
229
230inventory::collect!(BackendCapability);
231
232struct BackendRegistry {
234 registrations: Arc<[BackendRegistration]>,
235 capabilities: Arc<[(&'static str, bool)]>,
236 precedence: Arc<[(&'static str, u32)]>,
237}
238
239impl BackendRegistry {
240 fn build() -> Result<Self, BackendError> {
241 let registration_count = inventory::iter::<BackendRegistration>.into_iter().count();
242 let mut registrations = Vec::new();
243 crate::allocation::reserve_vec_to_capacity(
244 &mut registrations,
245 registration_count,
246 "Vyre backend registry",
247 "backend registration",
248 "reduce linked backend inventory",
249 )?;
250 registrations.extend(inventory::iter::<BackendRegistration>.into_iter().cloned());
251 registrations.sort_unstable_by(|left, right| left.id.cmp(right.id));
252 for registration in ®istrations {
253 validate_registration(registration)?;
254 }
255 for pair in registrations.windows(2) {
256 if pair[0].id == pair[1].id {
257 return Err(BackendError::new(format!(
258 "duplicate backend registration `{}`. Fix: keep one concrete provider for each backend id.",
259 pair[0].id
260 )));
261 }
262 }
263
264 let mut targets = Vec::new();
265 crate::allocation::reserve_vec_to_capacity(
266 &mut targets,
267 registrations.len(),
268 "Vyre backend registry",
269 "target identity",
270 "reduce linked backend inventory",
271 )?;
272 targets.extend(
273 registrations
274 .iter()
275 .map(|registration| (registration.target_id.as_str(), registration.id)),
276 );
277 targets.sort_unstable();
278 for pair in targets.windows(2) {
279 if pair[0].0 == pair[1].0 {
280 return Err(BackendError::new(format!(
281 "target `{}` is claimed by backend providers `{}` and `{}`. Fix: keep one concrete provider for each target identity.",
282 pair[0].0, pair[0].1, pair[1].1
283 )));
284 }
285 }
286
287 let capabilities = freeze_capabilities(®istrations)?;
288 let precedence = freeze_precedence(®istrations)?;
289 Ok(Self {
290 registrations: Arc::from(registrations),
291 capabilities,
292 precedence,
293 })
294 }
295
296 fn registration(&self, id: &str) -> Option<&BackendRegistration> {
297 self.registrations
298 .binary_search_by_key(&id, |registration| registration.id)
299 .ok()
300 .map(|index| &self.registrations[index])
301 }
302
303 fn dispatches(&self, id: &str) -> bool {
304 self.capabilities
305 .binary_search_by_key(&id, |(backend_id, _)| *backend_id)
306 .ok()
307 .is_some_and(|index| self.capabilities[index].1)
308 }
309
310 fn precedence(&self, id: &str) -> u32 {
311 self.precedence
312 .binary_search_by_key(&id, |(backend_id, _)| *backend_id)
313 .ok()
314 .map_or(u32::MAX, |index| self.precedence[index].1)
315 }
316}
317
318fn validate_registration(registration: &BackendRegistration) -> Result<(), BackendError> {
319 validate_registry_identity("backend", registration.id)?;
320 if let Some(format) = registration.payload_format {
321 validate_registry_identity("target payload format", format)?;
322 }
323 if registration.target_compiler.is_some() != registration.payload_format.is_some() {
324 return Err(BackendError::new(format!(
325 "backend `{}` must register its target compiler and payload format together. Fix: provide both target fields or leave both absent.",
326 registration.id
327 )));
328 }
329 Ok(())
330}
331
332fn validate_registry_identity(kind: &str, identity: &str) -> Result<(), BackendError> {
333 if identity.is_empty() || identity.trim() != identity {
334 return Err(BackendError::new(format!(
335 "{kind} identity `{identity}` is empty or whitespace-padded. Fix: declare a stable non-empty identity without surrounding whitespace."
336 )));
337 }
338 Ok(())
339}
340
341fn freeze_capabilities(
342 registrations: &[BackendRegistration],
343) -> Result<Arc<[(&'static str, bool)]>, BackendError> {
344 let count = inventory::iter::<BackendCapability>.into_iter().count();
345 let mut entries = Vec::new();
346 crate::allocation::reserve_vec_to_capacity(
347 &mut entries,
348 count,
349 "Vyre backend registry",
350 "dispatch capability",
351 "reduce linked backend capability declarations",
352 )?;
353 entries.extend(
354 inventory::iter::<BackendCapability>
355 .into_iter()
356 .map(|entry| (entry.id, entry.dispatches)),
357 );
358 entries.sort_unstable_by_key(|entry| entry.0);
359 validate_metadata_ids(registrations, &entries, "dispatch capability")?;
360 Ok(Arc::from(entries))
361}
362
363fn freeze_precedence(
364 registrations: &[BackendRegistration],
365) -> Result<Arc<[(&'static str, u32)]>, BackendError> {
366 let count = inventory::iter::<BackendPrecedence>.into_iter().count();
367 let mut entries = Vec::new();
368 crate::allocation::reserve_vec_to_capacity(
369 &mut entries,
370 count,
371 "Vyre backend registry",
372 "backend precedence",
373 "reduce linked backend precedence declarations",
374 )?;
375 entries.extend(
376 inventory::iter::<BackendPrecedence>
377 .into_iter()
378 .map(|entry| (entry.id, entry.rank)),
379 );
380 entries.sort_unstable_by_key(|entry| entry.0);
381 validate_metadata_ids(registrations, &entries, "backend precedence")?;
382 Ok(Arc::from(entries))
383}
384
385fn validate_metadata_ids<T>(
386 registrations: &[BackendRegistration],
387 entries: &[(&'static str, T)],
388 kind: &str,
389) -> Result<(), BackendError> {
390 for entry in entries {
391 validate_registry_identity(kind, entry.0)?;
392 if registrations
393 .binary_search_by_key(&entry.0, |registration| registration.id)
394 .is_err()
395 {
396 return Err(BackendError::new(format!(
397 "{kind} metadata names unregistered backend `{}`. Fix: submit one BackendRegistration with the same id or delete the orphaned metadata.",
398 entry.0
399 )));
400 }
401 }
402 for pair in entries.windows(2) {
403 if pair[0].0 == pair[1].0 {
404 return Err(BackendError::new(format!(
405 "duplicate {kind} metadata for backend `{}`. Fix: keep one owner-local metadata submission per backend.",
406 pair[0].0
407 )));
408 }
409 }
410 Ok(())
411}
412
413fn backend_registry() -> Result<&'static BackendRegistry, BackendError> {
414 static REGISTRY: LazyLock<Result<BackendRegistry, BackendError>> =
415 LazyLock::new(BackendRegistry::build);
416 match &*REGISTRY {
417 Ok(registry) => Ok(registry),
418 Err(error) => Err(error.clone()),
419 }
420}
421
422pub fn registered_backends() -> Result<&'static [BackendRegistration], BackendError> {
433 Ok(backend_registry()?.registrations.as_ref())
434}
435
436pub(super) fn registered_backend(
437 id: &str,
438) -> Result<Option<&'static BackendRegistration>, BackendError> {
439 Ok(backend_registry()?.registration(id))
440}
441
442pub(super) fn registered_backend_dispatches(id: &str) -> Result<bool, BackendError> {
443 Ok(backend_registry()?.dispatches(id))
444}
445
446pub(super) fn registered_backend_precedence(id: &str) -> Result<u32, BackendError> {
447 Ok(backend_registry()?.precedence(id))
448}