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 custom_types(&self) -> &[CustomTypeDefinition] {
77 &self.custom_types
78 }
79
80 pub(crate) fn into_parts(self) -> HostedPlannedModuleParts {
81 HostedPlannedModuleParts {
82 id: self.id,
83 package: self.package,
84 module: self.module,
85 source_context: self.source_context,
86 custom_types: self.custom_types,
87 external_types: self.external_types,
88 constants: self.constants,
89 functions: self.functions,
90 anonymous_functions: self.anonymous_functions,
91 }
92 }
93}
94
95impl HostedFunctionTemplate {
96 pub(crate) fn name(&self) -> &EcoString {
97 match self {
98 Self::GleamBody(function) => function.name(),
99 Self::HostTemplate(function) => function.name(),
100 }
101 }
102
103 pub(crate) fn signature(&self) -> &crate::plan::FunctionTemplateSignature {
104 match self {
105 Self::GleamBody(function) => function.signature(),
106 Self::HostTemplate(function) => function.signature(),
107 }
108 }
109
110 pub fn gleam_body(&self) -> Option<&FunctionTemplate> {
111 match self {
112 Self::GleamBody(function) => Some(function.as_ref()),
113 Self::HostTemplate(_) => None,
114 }
115 }
116
117 pub fn host_template(&self) -> Option<&HostFunctionTemplate> {
118 match self {
119 Self::GleamBody(_) => None,
120 Self::HostTemplate(function) => Some(function.as_ref()),
121 }
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use crate::frontend::{ModuleSource, PackageSource, compile_typed_host_program};
128 use crate::host::{HostModule, HostProviderSet};
129 use crate::planner::plan_host_program;
130 use num_bigint::BigInt;
131
132 #[test]
133 fn function_templates_expose_exactly_one_body_owner() {
134 let hosts = HostProviderSet::new([HostModule::new("host_support", "host/math")
135 .expect("host module should be valid")
136 .with_function("identity", |value: BigInt| value)
137 .expect("host function should be valid")])
138 .expect("host modules should be unique");
139 let source = r#"
140import host/math
141
142pub fn main() {
143 math.identity(1)
144}
145"#;
146 let typed = compile_typed_host_program(
147 "application",
148 "main",
149 [PackageSource::new(
150 "application",
151 ["host_support"],
152 [ModuleSource::new("main", "main.gleam", source)],
153 )],
154 hosts,
155 )
156 .expect("host program should compile");
157 let plan = plan_host_program(typed).expect("host program should plan");
158 let host = &plan.modules()[0].functions()[0];
159 let source = &plan.modules()[1].functions()[0];
160
161 assert_eq!(
162 host.host_template()
163 .expect("source-less function should own a host template")
164 .name(),
165 "identity",
166 );
167 assert!(host.gleam_body().is_none());
168 assert_eq!(
169 source
170 .gleam_body()
171 .expect("source function should own a Gleam body")
172 .name(),
173 "main",
174 );
175 assert!(source.host_template().is_none());
176 }
177}