wit_component/
dummy.rs

1use wit_parser::abi::WasmType;
2use wit_parser::{
3    Function, LiftLowerAbi, ManglingAndAbi, Resolve, ResourceIntrinsic, TypeDefKind, TypeId,
4    WasmExport, WasmExportKind, WasmImport, WorldId, WorldItem, WorldKey,
5};
6
7/// Generate a dummy implementation core Wasm module for a given WIT document
8pub fn dummy_module(resolve: &Resolve, world: WorldId, mangling: ManglingAndAbi) -> Vec<u8> {
9    let world = &resolve.worlds[world];
10    let mut wat = String::new();
11    wat.push_str("(module\n");
12    for (name, import) in world.imports.iter() {
13        match import {
14            WorldItem::Function(func) => {
15                push_imported_func(&mut wat, resolve, None, func, mangling);
16            }
17            WorldItem::Interface { id: import, .. } => {
18                for (_, func) in resolve.interfaces[*import].functions.iter() {
19                    push_imported_func(&mut wat, resolve, Some(name), func, mangling);
20                }
21                for (_, ty) in resolve.interfaces[*import].types.iter() {
22                    push_imported_type_intrinsics(&mut wat, resolve, Some(name), *ty, mangling);
23                }
24            }
25            WorldItem::Type(id) => {
26                push_imported_type_intrinsics(&mut wat, resolve, None, *id, mangling);
27            }
28        }
29    }
30
31    if mangling.is_async() {
32        push_root_async_intrinsics(&mut wat);
33    }
34
35    // Append any intrinsics which are imported but used in exported items
36    // (e.g. resources)
37    for (name, export) in world.exports.iter() {
38        match export {
39            WorldItem::Function(func) => {
40                push_exported_func_intrinsics(&mut wat, resolve, None, func, mangling);
41            }
42            WorldItem::Interface { id: export, .. } => {
43                for (_, func) in resolve.interfaces[*export].functions.iter() {
44                    push_exported_func_intrinsics(&mut wat, resolve, Some(name), func, mangling);
45                }
46                for (_, ty) in resolve.interfaces[*export].types.iter() {
47                    push_exported_type_intrinsics(&mut wat, resolve, Some(name), *ty, mangling);
48                }
49            }
50            WorldItem::Type(_) => {}
51        }
52    }
53
54    for (name, export) in world.exports.iter() {
55        match export {
56            WorldItem::Function(func) => {
57                push_func_export(&mut wat, resolve, None, func, mangling);
58            }
59            WorldItem::Interface { id: export, .. } => {
60                for (_, func) in resolve.interfaces[*export].functions.iter() {
61                    push_func_export(&mut wat, resolve, Some(name), func, mangling);
62                }
63                for (_, ty) in resolve.interfaces[*export].types.iter() {
64                    push_exported_resource_functions(&mut wat, resolve, name, *ty, mangling);
65                }
66            }
67            WorldItem::Type(_) => {}
68        }
69    }
70
71    let memory = resolve.wasm_export_name(mangling, WasmExport::Memory);
72    wat.push_str(&format!("(memory (export {memory:?}) 0)\n"));
73    let realloc = resolve.wasm_export_name(mangling, WasmExport::Realloc);
74    wat.push_str(&format!(
75        "(func (export {realloc:?}) (param i32 i32 i32 i32) (result i32) unreachable)\n"
76    ));
77
78    let initialize = resolve.wasm_export_name(mangling, WasmExport::Initialize);
79    wat.push_str(&format!("(func (export {initialize:?}))"));
80    wat.push_str(")\n");
81
82    return wat::parse_str(&wat).unwrap();
83}
84
85fn push_imported_func(
86    wat: &mut String,
87    resolve: &Resolve,
88    interface: Option<&WorldKey>,
89    func: &Function,
90    mangling: ManglingAndAbi,
91) {
92    let sig = resolve.wasm_signature(mangling.import_variant(), func);
93
94    let (module, name) = resolve.wasm_import_name(mangling, WasmImport::Func { interface, func });
95    wat.push_str(&format!("(import {module:?} {name:?} (func"));
96    push_tys(wat, "param", &sig.params);
97    push_tys(wat, "result", &sig.results);
98    wat.push_str("))\n");
99
100    if mangling.is_async() {
101        push_imported_future_and_stream_intrinsics(wat, resolve, "", interface, func);
102    }
103}
104
105fn push_imported_type_intrinsics(
106    wat: &mut String,
107    resolve: &Resolve,
108    interface: Option<&WorldKey>,
109    resource: TypeId,
110    mangling: ManglingAndAbi,
111) {
112    let ty = &resolve.types[resource];
113    match ty.kind {
114        TypeDefKind::Resource => {
115            let (module, name) = resolve.wasm_import_name(
116                // Force using a sync ABI here at this time as support for async
117                // resource drop isn't implemented yet.
118                mangling.sync(),
119                WasmImport::ResourceIntrinsic {
120                    interface,
121                    resource,
122                    intrinsic: ResourceIntrinsic::ImportedDrop,
123                },
124            );
125            wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
126
127            if mangling.is_async() {
128                // TODO: when wit-component supports async resource drop,
129                // implement it here too.
130                // let name = format!("[async-lower]{name}");
131                // wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
132            }
133        }
134
135        // No other types with intrinsics at this time (futures/streams are
136        // relative to where they show up in function types.
137        _ => {}
138    }
139}
140
141fn push_exported_func_intrinsics(
142    wat: &mut String,
143    resolve: &Resolve,
144    interface: Option<&WorldKey>,
145    func: &Function,
146    mangling: ManglingAndAbi,
147) {
148    if !mangling.is_async() {
149        return;
150    }
151
152    // For exported async functions, generate a `task.return` intrinsic.
153    let (module, name, sig) = func.task_return_import(resolve, interface, mangling.mangling());
154    wat.push_str(&format!("(import {module:?} {name:?} (func"));
155    push_tys(wat, "param", &sig.params);
156    push_tys(wat, "result", &sig.results);
157    wat.push_str("))\n");
158
159    push_imported_future_and_stream_intrinsics(wat, resolve, "[export]", interface, func);
160}
161
162fn push_imported_future_and_stream_intrinsics(
163    wat: &mut String,
164    resolve: &Resolve,
165    module_prefix: &str,
166    interface: Option<&WorldKey>,
167    func: &Function,
168) {
169    let module = match interface {
170        Some(key) => format!("{module_prefix}{}", resolve.name_world_key(key)),
171        None => format!("{module_prefix}$root"),
172    };
173    let name = &func.name;
174
175    for (i, id) in func
176        .find_futures_and_streams(resolve)
177        .into_iter()
178        .enumerate()
179    {
180        match &resolve.types[id].kind {
181            TypeDefKind::Future(_) => {
182                wat.push_str(&format!(
183                    r#"
184(import {module:?} "[future-new-{i}]{name}" (func (result i64)))
185(import {module:?} "[future-read-{i}]{name}" (func (param i32 i32) (result i32)))
186(import {module:?} "[future-write-{i}]{name}" (func (param i32 i32) (result i32)))
187(import {module:?} "[future-cancel-read-{i}]{name}" (func (param i32) (result i32)))
188(import {module:?} "[future-cancel-write-{i}]{name}" (func (param i32) (result i32)))
189(import {module:?} "[future-drop-readable-{i}]{name}" (func (param i32)))
190(import {module:?} "[future-drop-writable-{i}]{name}" (func (param i32)))
191(import {module:?} "[async-lower][future-read-{i}]{name}" (func (param i32 i32) (result i32)))
192(import {module:?} "[async-lower][future-write-{i}]{name}" (func (param i32 i32) (result i32)))
193
194;; deferred behind ๐Ÿš
195;;(import {module:?} "[async-lower][future-cancel-read-{i}]{name}" (func (param i32) (result i32)))
196;;(import {module:?} "[async-lower][future-cancel-write-{i}]{name}" (func (param i32) (result i32)))
197"#
198                ));
199            }
200            TypeDefKind::Stream(_) => {
201                wat.push_str(&format!(
202                    r#"
203(import {module:?} "[stream-new-{i}]{name}" (func (result i64)))
204(import {module:?} "[stream-read-{i}]{name}" (func (param i32 i32 i32) (result i32)))
205(import {module:?} "[stream-write-{i}]{name}" (func (param i32 i32 i32) (result i32)))
206(import {module:?} "[stream-cancel-read-{i}]{name}" (func (param i32) (result i32)))
207(import {module:?} "[stream-cancel-write-{i}]{name}" (func (param i32) (result i32)))
208(import {module:?} "[stream-drop-readable-{i}]{name}" (func (param i32)))
209(import {module:?} "[stream-drop-writable-{i}]{name}" (func (param i32)))
210(import {module:?} "[async-lower][stream-read-{i}]{name}" (func (param i32 i32 i32) (result i32)))
211(import {module:?} "[async-lower][stream-write-{i}]{name}" (func (param i32 i32 i32) (result i32)))
212
213;; deferred behind ๐Ÿš
214;;(import {module:?} "[async-lower][stream-cancel-read-{i}]{name}" (func (param i32) (result i32)))
215;;(import {module:?} "[async-lower][stream-cancel-write-{i}]{name}" (func (param i32) (result i32)))
216"#
217                ));
218            }
219            _ => unreachable!(),
220        }
221    }
222}
223
224fn push_exported_type_intrinsics(
225    wat: &mut String,
226    resolve: &Resolve,
227    interface: Option<&WorldKey>,
228    resource: TypeId,
229    mangling: ManglingAndAbi,
230) {
231    let ty = &resolve.types[resource];
232    match ty.kind {
233        TypeDefKind::Resource => {
234            let intrinsics = [
235                (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
236                (
237                    ResourceIntrinsic::ExportedNew,
238                    "(func (param i32) (result i32))",
239                ),
240                (
241                    ResourceIntrinsic::ExportedRep,
242                    "(func (param i32) (result i32))",
243                ),
244            ];
245            for (intrinsic, sig) in intrinsics {
246                let (module, name) = resolve.wasm_import_name(
247                    mangling.sync(),
248                    WasmImport::ResourceIntrinsic {
249                        interface,
250                        resource,
251                        intrinsic,
252                    },
253                );
254                wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
255            }
256        }
257
258        // No other types with intrinsics at this time (futures/streams
259        // relative to where they are in a function).
260        _ => {}
261    }
262}
263
264fn push_exported_resource_functions(
265    wat: &mut String,
266    resolve: &Resolve,
267    interface: &WorldKey,
268    resource: TypeId,
269    mangling: ManglingAndAbi,
270) {
271    let ty = &resolve.types[resource];
272    match ty.kind {
273        TypeDefKind::Resource => {}
274        _ => return,
275    }
276    // Feign destructors for any resource that this interface
277    // exports
278    let name = resolve.wasm_export_name(
279        mangling,
280        WasmExport::ResourceDtor {
281            interface,
282            resource,
283        },
284    );
285    wat.push_str(&format!("(func (export {name:?}) (param i32))"));
286}
287
288fn push_func_export(
289    wat: &mut String,
290    resolve: &Resolve,
291    interface: Option<&WorldKey>,
292    func: &Function,
293    mangling: ManglingAndAbi,
294) {
295    let sig = resolve.wasm_signature(mangling.export_variant(), func);
296    let name = resolve.wasm_export_name(
297        mangling,
298        WasmExport::Func {
299            interface,
300            func,
301            kind: WasmExportKind::Normal,
302        },
303    );
304    wat.push_str(&format!("(func (export \"{name}\")"));
305    push_tys(wat, "param", &sig.params);
306    push_tys(wat, "result", &sig.results);
307    wat.push_str(" unreachable)\n");
308
309    match mangling {
310        ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
311            let name = resolve.wasm_export_name(
312                mangling,
313                WasmExport::Func {
314                    interface,
315                    func,
316                    kind: WasmExportKind::PostReturn,
317                },
318            );
319            wat.push_str(&format!("(func (export \"{name}\")"));
320            push_tys(wat, "param", &sig.results);
321            wat.push_str(")\n");
322        }
323        ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
324            let name = resolve.wasm_export_name(
325                mangling,
326                WasmExport::Func {
327                    interface,
328                    func,
329                    kind: WasmExportKind::Callback,
330                },
331            );
332            wat.push_str(&format!(
333                "(func (export \"{name}\") (param i32 i32 i32) (result i32) unreachable)\n"
334            ));
335        }
336        ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
337    }
338}
339
340fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
341    if params.is_empty() {
342        return;
343    }
344    dst.push_str(" (");
345    dst.push_str(desc);
346    for ty in params {
347        dst.push(' ');
348        match ty {
349            WasmType::I32 => dst.push_str("i32"),
350            WasmType::I64 => dst.push_str("i64"),
351            WasmType::F32 => dst.push_str("f32"),
352            WasmType::F64 => dst.push_str("f64"),
353            WasmType::Pointer => dst.push_str("i32"),
354            WasmType::PointerOrI64 => dst.push_str("i64"),
355            WasmType::Length => dst.push_str("i32"),
356        }
357    }
358    dst.push(')');
359}
360
361fn push_root_async_intrinsics(dst: &mut String) {
362    dst.push_str(
363        r#"
364(import "[export]$root" "[task-cancel]" (func))
365(import "$root" "[backpressure-set]" (func (param i32)))
366(import "$root" "[backpressure-inc]" (func))
367(import "$root" "[backpressure-dec]" (func))
368(import "$root" "[waitable-set-new]" (func (result i32)))
369(import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32)))
370(import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
371(import "$root" "[waitable-set-drop]" (func (param i32)))
372(import "$root" "[waitable-join]" (func (param i32 i32)))
373(import "$root" "[thread-yield]" (func (result i32)))
374(import "$root" "[subtask-drop]" (func (param i32)))
375(import "$root" "[subtask-cancel]" (func (param i32) (result i32)))
376(import "$root" "[context-get-0]" (func (result i32)))
377(import "$root" "[context-set-0]" (func (param i32)))
378
379;; deferred behind ๐Ÿงต upstream
380;;(import "$root" "[cancellable][waitable-set-wait]" (func (param i32 i32) (result i32)))
381;;(import "$root" "[cancellable][waitable-set-poll]" (func (param i32 i32) (result i32)))
382;;(import "$root" "[cancellable][thread-yield]" (func (result i32)))
383;;(import "$root" "[context-get-1]" (func (result i32)))
384;;(import "$root" "[context-set-1]" (func (param i32)))
385
386;; deferred behind ๐Ÿ“ upstream
387;;(import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
388;;(import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32)))
389;;(import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32)))
390;;(import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32)))
391;;(import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32)))
392;;(import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32)))
393;;(import "$root" "[error-context-drop]" (func (param i32)))
394"#,
395    );
396}