fce_wit_parser/extractor/
functions.rs

1/*
2 * Copyright 2020 Fluence Labs Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::Result;
18use crate::WITParserError;
19use fce_wit_interfaces::FCEWITInterfaces;
20
21use wasmer_wit::IRecordType;
22use wasmer_wit::ast::FunctionArg as IFunctionArg;
23use wasmer_wit::IType;
24use serde::Serialize;
25use serde::Deserialize;
26
27use std::collections::HashMap;
28use std::rc::Rc;
29
30pub type FCERecordTypes = HashMap<u64, Rc<IRecordType>>;
31
32#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
33pub struct FCEFunctionSignature {
34    pub name: Rc<String>,
35    pub arguments: Rc<Vec<IFunctionArg>>,
36    pub outputs: Rc<Vec<IType>>,
37}
38
39#[derive(PartialEq, Eq, Debug, Clone, Serialize)]
40pub struct FCEModuleInterface {
41    pub record_types: FCERecordTypes,
42    pub function_signatures: Vec<FCEFunctionSignature>,
43}
44
45pub fn get_interface(fce_it_interface: &FCEWITInterfaces<'_>) -> Result<ServiceInterface> {
46    let fce_interface = get_raw_interface(fce_it_interface)?;
47    let service_interface = into_service_interface(fce_interface);
48
49    Ok(service_interface)
50}
51
52pub fn get_raw_interface(fce_it_interface: &FCEWITInterfaces<'_>) -> Result<FCEModuleInterface> {
53    let function_signatures = get_exports(fce_it_interface)?;
54    let record_types = extract_record_types(fce_it_interface);
55
56    let fce_interface = FCEModuleInterface {
57        record_types,
58        function_signatures,
59    };
60
61    Ok(fce_interface)
62}
63
64fn get_exports(wit: &FCEWITInterfaces<'_>) -> Result<Vec<FCEFunctionSignature>> {
65    use fce_wit_interfaces::WITAstType;
66
67    wit.implementations()
68        .filter_map(|(adapter_function_type, core_function_type)| {
69            wit.exports_by_type(*core_function_type)
70                .map(|export_function_name| (adapter_function_type, export_function_name))
71        })
72        .map(|(adapter_function_type, export_function_names)| {
73            export_function_names
74                .iter()
75                .map(move |export_function_name| (*adapter_function_type, export_function_name))
76        })
77        .flatten()
78        .map(|(adapter_function_type, export_function_name)| {
79            let wit_type = wit.type_by_idx_r(adapter_function_type).unwrap();
80
81            match wit_type {
82                WITAstType::Function {
83                    arguments,
84                    output_types,
85                } => {
86                    let signature = FCEFunctionSignature {
87                        name: Rc::new(export_function_name.to_string()),
88                        arguments: arguments.clone(),
89                        outputs: output_types.clone(),
90                    };
91                    Ok(signature)
92                }
93                _ => Err(WITParserError::IncorrectITFormat(format!(
94                    "type with idx = {} isn't a function type",
95                    adapter_function_type
96                ))),
97            }
98        })
99        .collect::<Result<Vec<FCEFunctionSignature>>>()
100}
101
102fn extract_record_types(wit: &FCEWITInterfaces<'_>) -> FCERecordTypes {
103    use fce_wit_interfaces::WITAstType;
104
105    let (record_types_by_id, _) = wit.types().fold(
106        (HashMap::new(), 0u64),
107        |(mut record_types_by_id, id), ty| {
108            match ty {
109                WITAstType::Record(record_type) => {
110                    record_types_by_id.insert(id, record_type.clone());
111                }
112                WITAstType::Function { .. } => {}
113            };
114            (record_types_by_id, id + 1)
115        },
116    );
117
118    record_types_by_id
119}
120
121#[derive(Serialize)]
122pub struct FunctionSignature {
123    pub name: String,
124    pub arguments: Vec<(String, String)>,
125    pub output_types: Vec<String>,
126}
127
128#[derive(Serialize)]
129pub struct RecordType {
130    pub name: String,
131    pub id: u64,
132    pub fields: Vec<(String, String)>,
133}
134
135#[derive(Serialize)]
136pub struct ServiceInterface {
137    pub function_signatures: Vec<FunctionSignature>,
138    pub record_types: Vec<RecordType>,
139}
140
141pub(crate) fn into_service_interface(fce_interface: FCEModuleInterface) -> ServiceInterface {
142    let record_types = fce_interface.record_types;
143
144    let function_signatures = fce_interface
145        .function_signatures
146        .into_iter()
147        .map(|sign| serialize_function_signature(sign, &record_types))
148        .collect();
149
150    let record_types = record_types
151        .iter()
152        .map(|(id, record)| serialize_record_type(*id, record.clone(), &record_types))
153        .collect::<Vec<_>>();
154
155    ServiceInterface {
156        function_signatures,
157        record_types,
158    }
159}
160
161fn serialize_function_signature(
162    signature: FCEFunctionSignature,
163    record_types: &FCERecordTypes,
164) -> FunctionSignature {
165    let arguments = signature
166        .arguments
167        .iter()
168        .map(|arg| (arg.name.clone(), itype_text_view(&arg.ty, record_types)))
169        .collect();
170
171    let output_types = signature
172        .outputs
173        .iter()
174        .map(|itype| itype_text_view(itype, record_types))
175        .collect();
176
177    FunctionSignature {
178        name: signature.name.to_string(),
179        arguments,
180        output_types,
181    }
182}
183
184fn serialize_record_type(
185    id: u64,
186    record: Rc<IRecordType>,
187    record_types: &FCERecordTypes,
188) -> RecordType {
189    let fields = record
190        .fields
191        .iter()
192        .map(|field| (field.name.clone(), itype_text_view(&field.ty, record_types)))
193        .collect::<Vec<_>>();
194
195    RecordType {
196        name: record.name.clone(),
197        id,
198        fields,
199    }
200}
201
202fn itype_text_view(arg_ty: &IType, record_types: &FCERecordTypes) -> String {
203    match arg_ty {
204        IType::Record(record_type_id) => {
205            // unwrap is safe because FaaSInterface here is well-formed
206            // (it was checked on the module startup stage)
207            let record = record_types.get(record_type_id).unwrap();
208            record.name.clone()
209        }
210        IType::Array(array_ty) => format!("Array<{}>", itype_text_view(array_ty, record_types)),
211        t => format!("{:?}", t),
212    }
213}