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