golem_scalajs_wit_bindgen/codegen/
function.rs

1// Copyright 2024 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Display;
16
17use color_eyre::Result;
18use convert_case::{Case, Casing};
19use wit_parser::{Function as WitFunction, Results as WitResults, Type as WitType};
20
21use super::Render;
22use crate::types::{Type, TypeMap};
23
24/// Represents the name of a function param in Scala
25struct ParamName(String);
26
27impl Display for ParamName {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        write!(f, "{}", self.0)
30    }
31}
32
33impl From<String> for ParamName {
34    fn from(name: String) -> Self {
35        Self(name.to_case(Case::Camel))
36    }
37}
38
39/// Represents a function param in Scala
40struct Param {
41    /// The param name
42    name: ParamName,
43
44    /// The Scala type associated to the param
45    ty: Type,
46}
47
48impl Param {
49    // Constructs a `Param` from WIT
50    pub fn from_wit(name: String, ty: WitType, type_map: &TypeMap) -> Result<Self> {
51        Ok(Self {
52            name: ParamName::from(name),
53            ty: Type::from_wit(ty, type_map)?,
54        })
55    }
56}
57
58/// Represents a function name in Scala
59#[derive(Clone)]
60struct FunctionName(String);
61
62impl Display for FunctionName {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        write!(f, "{}", self.0)
65    }
66}
67
68impl From<String> for FunctionName {
69    fn from(name: String) -> Self {
70        Self(name.to_case(Case::Camel))
71    }
72}
73
74/// Represents a function in Scala
75pub struct Function {
76    /// The function name
77    name: FunctionName,
78
79    /// The params of the function
80    params: Vec<Param>,
81
82    /// The outputs of the function
83    outs: Vec<Type>,
84}
85
86impl Function {
87    /// Constructs a `Function` from WIT
88    pub fn from_wit(function: WitFunction, type_map: &TypeMap) -> Result<Self> {
89        let params: Result<Vec<Param>> = function
90            .params
91            .into_iter()
92            .map(|(name, ty)| Param::from_wit(name, ty, type_map))
93            .collect();
94
95        let outs: Result<Vec<Type>> = match function.results {
96            WitResults::Named(params) => params
97                .iter()
98                .map(|(_, ty)| Type::from_wit(*ty, type_map))
99                .collect(),
100            WitResults::Anon(ty) => Type::from_wit(ty, type_map).map(|ty| vec![ty]),
101        };
102
103        Ok(Self {
104            name: FunctionName::from(function.name),
105            params: params?,
106            outs: outs?,
107        })
108    }
109}
110
111impl Render for Function {
112    fn render(self) -> Result<String> {
113        let params = self
114            .params
115            .iter()
116            .map(|Param { name, ty }| format!("{name}: {ty}"))
117            .collect::<Vec<_>>()
118            .join(", ");
119
120        let out = {
121            let outs = self.outs.iter().map(Type::to_string).collect::<Vec<_>>();
122
123            if outs.is_empty() {
124                "Unit".to_owned()
125            } else if outs.len() == 1 {
126                outs.first().unwrap().clone()
127            } else {
128                format!("({})", outs.join(", "))
129            }
130        };
131
132        let name = self.name;
133
134        Ok(format!("def {name}({params}): {out}"))
135    }
136}