geam_core/plan/host/
module.rs1use super::HostFunctionTemplate;
2use crate::plan::{
3 ConstantTemplates, CustomTypeDefinition, ExternalTypeDefinition, FunctionTemplate, ModuleId,
4 SourceContext,
5};
6use ecow::EcoString;
7
8pub struct HostedPlannedModule {
9 id: ModuleId,
10 package: EcoString,
11 module: EcoString,
12 source_context: Option<SourceContext>,
13 custom_types: Vec<CustomTypeDefinition>,
14 external_types: Vec<ExternalTypeDefinition>,
15 constants: ConstantTemplates,
16 functions: Vec<HostedFunctionTemplate>,
17 anonymous_functions: Vec<FunctionTemplate>,
18}
19
20pub enum HostedFunctionTemplate {
21 GleamBody(Box<FunctionTemplate>),
22 HostTemplate(Box<HostFunctionTemplate>),
23}
24
25pub(crate) struct HostedPlannedModuleParts {
26 pub(crate) id: ModuleId,
27 pub(crate) package: EcoString,
28 pub(crate) module: EcoString,
29 pub(crate) source_context: Option<SourceContext>,
30 pub(crate) custom_types: Vec<CustomTypeDefinition>,
31 pub(crate) external_types: Vec<ExternalTypeDefinition>,
32 pub(crate) constants: ConstantTemplates,
33 pub(crate) functions: Vec<HostedFunctionTemplate>,
34 pub(crate) anonymous_functions: Vec<FunctionTemplate>,
35}
36
37impl HostedPlannedModule {
38 pub(crate) fn new(parts: HostedPlannedModuleParts) -> Self {
39 Self {
40 id: parts.id,
41 package: parts.package,
42 module: parts.module,
43 source_context: parts.source_context,
44 custom_types: parts.custom_types,
45 external_types: parts.external_types,
46 constants: parts.constants,
47 functions: parts.functions,
48 anonymous_functions: parts.anonymous_functions,
49 }
50 }
51
52 pub fn id(&self) -> ModuleId {
53 self.id
54 }
55
56 pub fn package(&self) -> &EcoString {
57 &self.package
58 }
59
60 pub fn module(&self) -> &EcoString {
61 &self.module
62 }
63
64 pub fn source_context(&self) -> Option<&SourceContext> {
65 self.source_context.as_ref()
66 }
67
68 pub fn functions(&self) -> &[HostedFunctionTemplate] {
69 &self.functions
70 }
71
72 pub fn external_types(&self) -> &[ExternalTypeDefinition] {
73 &self.external_types
74 }
75
76 pub(crate) fn into_parts(self) -> HostedPlannedModuleParts {
77 HostedPlannedModuleParts {
78 id: self.id,
79 package: self.package,
80 module: self.module,
81 source_context: self.source_context,
82 custom_types: self.custom_types,
83 external_types: self.external_types,
84 constants: self.constants,
85 functions: self.functions,
86 anonymous_functions: self.anonymous_functions,
87 }
88 }
89}
90
91impl HostedFunctionTemplate {
92 pub fn gleam_body(&self) -> Option<&FunctionTemplate> {
93 match self {
94 Self::GleamBody(function) => Some(function.as_ref()),
95 Self::HostTemplate(_) => None,
96 }
97 }
98
99 pub fn host_template(&self) -> Option<&HostFunctionTemplate> {
100 match self {
101 Self::GleamBody(_) => None,
102 Self::HostTemplate(function) => Some(function.as_ref()),
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use crate::frontend::{ModuleSource, PackageSource, compile_typed_host_program};
110 use crate::host::{HostModule, HostProviderSet};
111 use crate::planner::plan_host_program;
112 use num_bigint::BigInt;
113
114 #[test]
115 fn function_templates_expose_exactly_one_body_owner() {
116 let hosts = HostProviderSet::new([HostModule::new("host_support", "host/math")
117 .expect("host module should be valid")
118 .with_function("identity", |value: BigInt| value)
119 .expect("host function should be valid")])
120 .expect("host modules should be unique");
121 let source = r#"
122import host/math
123
124pub fn main() {
125 math.identity(1)
126}
127"#;
128 let typed = compile_typed_host_program(
129 "application",
130 "main",
131 [PackageSource::new(
132 "application",
133 ["host_support"],
134 [ModuleSource::new("main", "main.gleam", source)],
135 )],
136 hosts,
137 )
138 .expect("host program should compile");
139 let plan = plan_host_program(typed).expect("host program should plan");
140 let host = &plan.modules()[0].functions()[0];
141 let source = &plan.modules()[1].functions()[0];
142
143 assert_eq!(
144 host.host_template()
145 .expect("source-less function should own a host template")
146 .name(),
147 "identity",
148 );
149 assert!(host.gleam_body().is_none());
150 assert_eq!(
151 source
152 .gleam_body()
153 .expect("source function should own a Gleam body")
154 .name(),
155 "main",
156 );
157 assert!(source.host_template().is_none());
158 }
159}