Skip to main content

geam_core/plan/host/
module.rs

1use 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}