opy_rs/compiler/
integration.rs1use super::*;
4use std::sync::OnceLock;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct LinkReport {
9 pub catalog_ids_checked: usize,
10 pub domains_checked: usize,
11}
12
13pub(crate) struct CompilerContract {
14 pub(super) catalog: Catalog,
15 pub(super) manifest: &'static Manifest,
16 pub(super) links: LinkReport,
17}
18
19static COMPILER_CONTRACT: OnceLock<Result<CompilerContract, IntegrationError>> = OnceLock::new();
20
21pub(crate) fn cross_check_manifest(
25 manifest: &Manifest,
26 catalog: &Catalog,
27) -> Result<LinkReport, IntegrationError> {
28 #[cfg(test)]
29 crate::resource_metrics::record_contract_check();
30 let mut catalog_ids_checked = 0;
31 let mut domains_checked = 0;
32
33 for function in &manifest.functions {
34 if let Some(catalog_id) = &function.catalog_id {
35 let kind = match function.kind {
36 FunctionKind::Action | FunctionKind::MemberAction => Kind::Action,
37 FunctionKind::Value | FunctionKind::MemberValue => Kind::Value,
38 };
39 catalog_ids_checked += 1;
40 if catalog.entry(kind, catalog_id).is_none() {
41 return Err(IntegrationError::new(
42 "catalog-link-missing",
43 format!(
44 "manifest function '{}' links to missing {:?} catalog id '{}'",
45 function.id, kind, catalog_id
46 ),
47 None,
48 ));
49 }
50 }
51
52 for parameter in &function.params {
53 let Some(domain) = ¶meter.domain else {
54 continue;
55 };
56 if crate::lower::policy::is_contextual_domain(domain) {
57 continue;
58 }
59 domains_checked += 1;
60 if catalog.enum_domain(domain).is_none() {
61 return Err(IntegrationError::new(
62 "domain-link-missing",
63 format!(
64 "manifest function '{}' parameter '{}' links to missing enum domain '{}',",
65 function.id, parameter.name, domain
66 ),
67 None,
68 ));
69 }
70 }
71
72 if let Some(contextual) = crate::lower::policy::contextual_domain(&function.id) {
73 for option in contextual.options {
74 domains_checked += 1;
75 if catalog.enum_domain(option.domain).is_none() {
76 return Err(IntegrationError::new(
77 "domain-link-missing",
78 format!(
79 "manifest function '{}' contextual option links to missing enum domain '{}'",
80 function.id, option.domain
81 ),
82 None,
83 ));
84 }
85 }
86 }
87 }
88
89 Ok(LinkReport {
90 catalog_ids_checked,
91 domains_checked,
92 })
93}
94
95pub(crate) fn load_compiler_contract() -> Result<&'static CompilerContract, IntegrationError> {
96 COMPILER_CONTRACT
97 .get_or_init(|| {
98 let catalog = Catalog::builtin()
99 .map_err(|error| IntegrationError::new("catalog-load", error.to_string(), None))?;
100 let manifest = Manifest::builtin()
101 .map_err(|error| IntegrationError::new("manifest-load", error.to_string(), None))?;
102 let links = cross_check_manifest(manifest, &catalog)?;
103 Ok(CompilerContract {
104 catalog,
105 manifest,
106 links,
107 })
108 })
109 .as_ref()
110 .map_err(Clone::clone)
111}