Skip to main content

wasmer_interface_types/encoders/
wat.rs

1//! Writes the AST into a string representing WIT with its textual format.
2//!
3//! # Example
4//!
5//! ```rust
6//! use wasmer_interface_types::{
7//!     ast::{Adapter, Export, Implementation, Import, Interfaces, Type},
8//!     encoders::wat::*,
9//!     interpreter::Instruction,
10//!     types::InterfaceType,
11//! };
12//!
13//! let input: String = (&Interfaces {
14//!     types: vec![Type::Function {
15//!         inputs: vec![InterfaceType::I32],
16//!         outputs: vec![InterfaceType::S8],
17//!     }],
18//!     imports: vec![Import {
19//!         namespace: "ns",
20//!         name: "foo",
21//!         signature_type: 0,
22//!     }],
23//!     adapters: vec![Adapter {
24//!         function_type: 0,
25//!         instructions: vec![Instruction::ArgumentGet { index: 42 }],
26//!     }],
27//!     exports: vec![Export {
28//!         name: "bar",
29//!         function_type: 0,
30//!     }],
31//!     implementations: vec![Implementation {
32//!         core_function_type: 0,
33//!         adapter_function_type: 1,
34//!     }],
35//! })
36//!     .to_string();
37//! let output = r#";; Types
38//! (@interface type (func
39//!   (param i32)
40//!   (result s8)))
41//!
42//! ;; Imports
43//! (@interface import "ns" "foo" (func (type 0)))
44//!
45//! ;; Adapters
46//! (@interface func (type 0)
47//!   arg.get 42)
48//!
49//! ;; Exports
50//! (@interface export "bar" (func 0))
51//!
52//! ;; Implementations
53//! (@interface implement (func 0) (func 1))"#;
54//!
55//! assert_eq!(input, output);
56//! ```
57
58use crate::{ast::*, interpreter::Instruction, types::*};
59use std::string::ToString;
60
61/// Encode an `InterfaceType` into a string.
62impl ToString for &InterfaceType {
63    fn to_string(&self) -> String {
64        match self {
65            InterfaceType::S8 => "s8".to_string(),
66            InterfaceType::S16 => "s16".to_string(),
67            InterfaceType::S32 => "s32".to_string(),
68            InterfaceType::S64 => "s64".to_string(),
69            InterfaceType::U8 => "u8".to_string(),
70            InterfaceType::U16 => "u16".to_string(),
71            InterfaceType::U32 => "u32".to_string(),
72            InterfaceType::U64 => "u64".to_string(),
73            InterfaceType::F32 => "f32".to_string(),
74            InterfaceType::F64 => "f64".to_string(),
75            InterfaceType::String => "string".to_string(),
76            InterfaceType::Anyref => "anyref".to_string(),
77            InterfaceType::I32 => "i32".to_string(),
78            InterfaceType::I64 => "i64".to_string(),
79            InterfaceType::Record(record_type) => record_type.to_string(),
80        }
81    }
82}
83
84impl ToString for &RecordType {
85    fn to_string(&self) -> String {
86        format!(
87            "record{fields}",
88            fields = self
89                .fields
90                .iter()
91                .fold(String::new(), |mut accumulator, interface_type| {
92                    accumulator.push(' ');
93                    accumulator.push_str(&format!("(field {})", &interface_type.to_string()));
94                    accumulator
95                }),
96        )
97    }
98}
99
100/// Encode an `Instruction` into a string.
101impl ToString for &Instruction {
102    fn to_string(&self) -> String {
103        match self {
104            Instruction::ArgumentGet { index } => format!("arg.get {}", index),
105            Instruction::CallCore { function_index } => format!("call-core {}", function_index),
106            Instruction::S8FromI32 => "s8.from_i32".into(),
107            Instruction::S8FromI64 => "s8.from_i64".into(),
108            Instruction::S16FromI32 => "s16.from_i32".into(),
109            Instruction::S16FromI64 => "s16.from_i64".into(),
110            Instruction::S32FromI32 => "s32.from_i32".into(),
111            Instruction::S32FromI64 => "s32.from_i64".into(),
112            Instruction::S64FromI32 => "s64.from_i32".into(),
113            Instruction::S64FromI64 => "s64.from_i64".into(),
114            Instruction::I32FromS8 => "i32.from_s8".into(),
115            Instruction::I32FromS16 => "i32.from_s16".into(),
116            Instruction::I32FromS32 => "i32.from_s32".into(),
117            Instruction::I32FromS64 => "i32.from_s64".into(),
118            Instruction::I64FromS8 => "i64.from_s8".into(),
119            Instruction::I64FromS16 => "i64.from_s16".into(),
120            Instruction::I64FromS32 => "i64.from_s32".into(),
121            Instruction::I64FromS64 => "i64.from_s64".into(),
122            Instruction::U8FromI32 => "u8.from_i32".into(),
123            Instruction::U8FromI64 => "u8.from_i64".into(),
124            Instruction::U16FromI32 => "u16.from_i32".into(),
125            Instruction::U16FromI64 => "u16.from_i64".into(),
126            Instruction::U32FromI32 => "u32.from_i32".into(),
127            Instruction::U32FromI64 => "u32.from_i64".into(),
128            Instruction::U64FromI32 => "u64.from_i32".into(),
129            Instruction::U64FromI64 => "u64.from_i64".into(),
130            Instruction::I32FromU8 => "i32.from_u8".into(),
131            Instruction::I32FromU16 => "i32.from_u16".into(),
132            Instruction::I32FromU32 => "i32.from_u32".into(),
133            Instruction::I32FromU64 => "i32.from_u64".into(),
134            Instruction::I64FromU8 => "i64.from_u8".into(),
135            Instruction::I64FromU16 => "i64.from_u16".into(),
136            Instruction::I64FromU32 => "i64.from_u32".into(),
137            Instruction::I64FromU64 => "i64.from_u64".into(),
138            Instruction::StringLiftMemory => "string.lift_memory".into(),
139            Instruction::StringLowerMemory => "string.lower_memory".into(),
140            Instruction::StringSize => "string.size".into(),
141            Instruction::RecordLift { type_index } => format!("record.lift {}", type_index),
142            Instruction::RecordLower { type_index } => format!("record.lower {}", type_index),
143        }
144    }
145}
146
147/// Encode a list of `InterfaceType` representing inputs into a
148/// string.
149fn input_types_to_param(input_types: &[InterfaceType]) -> String {
150    if input_types.is_empty() {
151        "".into()
152    } else {
153        format!(
154            "\n  (param{})",
155            input_types
156                .iter()
157                .fold(String::new(), |mut accumulator, interface_type| {
158                    accumulator.push(' ');
159                    accumulator.push_str(&interface_type.to_string());
160                    accumulator
161                })
162        )
163    }
164}
165
166/// Encode a list of `InterfaceType` representing outputs into a
167/// string.
168fn output_types_to_result(output_types: &[InterfaceType]) -> String {
169    if output_types.is_empty() {
170        "".into()
171    } else {
172        format!(
173            "\n  (result{})",
174            output_types
175                .iter()
176                .fold(String::new(), |mut accumulator, interface_type| {
177                    accumulator.push(' ');
178                    accumulator.push_str(&interface_type.to_string());
179                    accumulator
180                })
181        )
182    }
183}
184
185/// Encode a `Type` into a string.
186impl<'input> ToString for &Type {
187    fn to_string(&self) -> String {
188        match self {
189            Type::Function { inputs, outputs } => format!(
190                r#"(@interface type (func{inputs}{outputs}))"#,
191                inputs = input_types_to_param(&inputs),
192                outputs = output_types_to_result(&outputs),
193            ),
194
195            Type::Record(record_type) => format!(
196                r#"(@interface type ({record_type}))"#,
197                record_type = record_type.to_string(),
198            ),
199        }
200    }
201}
202
203/// Encode an `Import` into a string.
204impl<'input> ToString for &Import<'input> {
205    fn to_string(&self) -> String {
206        format!(
207            r#"(@interface import "{namespace}" "{name}" (func (type {type})))"#,
208            namespace = self.namespace,
209            name = self.name,
210            type = self.signature_type,
211        )
212    }
213}
214
215/// Encode an `Adapter` into a string.
216impl ToString for &Adapter {
217    fn to_string(&self) -> String {
218        format!(
219            r#"(@interface func (type {function_type}){instructions})"#,
220            function_type = self.function_type,
221            instructions =
222                self.instructions
223                    .iter()
224                    .fold(String::new(), |mut accumulator, instruction| {
225                        accumulator.push_str("\n  ");
226                        accumulator.push_str(&instruction.to_string());
227                        accumulator
228                    }),
229        )
230    }
231}
232
233/// Encode an `Export` into a string.
234impl<'input> ToString for &Export<'input> {
235    fn to_string(&self) -> String {
236        format!(
237            r#"(@interface export "{name}" (func {type}))"#,
238            name = self.name,
239            type = self.function_type,
240        )
241    }
242}
243
244/// Encode an `Implementation` into a string.
245impl<'input> ToString for &Implementation {
246    fn to_string(&self) -> String {
247        format!(
248            r#"(@interface implement (func {core_function_type}) (func {adapter_function_type}))"#,
249            core_function_type = self.core_function_type,
250            adapter_function_type = self.adapter_function_type,
251        )
252    }
253}
254
255/// Encode an `Interfaces` into a string.
256impl<'input> ToString for &Interfaces<'input> {
257    fn to_string(&self) -> String {
258        let mut output = String::new();
259
260        let types = self
261            .types
262            .iter()
263            .fold(String::new(), |mut accumulator, ty| {
264                accumulator.push('\n');
265                accumulator.push_str(&ty.to_string());
266                accumulator
267            });
268
269        let imports = self
270            .imports
271            .iter()
272            .fold(String::new(), |mut accumulator, import| {
273                accumulator.push('\n');
274                accumulator.push_str(&import.to_string());
275                accumulator
276            });
277
278        let adapters = self
279            .adapters
280            .iter()
281            .fold(String::new(), |mut accumulator, adapter| {
282                accumulator.push('\n');
283                accumulator.push_str(&adapter.to_string());
284                accumulator
285            });
286
287        let exports = self
288            .exports
289            .iter()
290            .fold(String::new(), |mut accumulator, export| {
291                accumulator.push('\n');
292                accumulator.push_str(&export.to_string());
293                accumulator
294            });
295
296        let implementations =
297            self.implementations
298                .iter()
299                .fold(String::new(), |mut accumulator, implementation| {
300                    accumulator.push('\n');
301                    accumulator.push_str(&implementation.to_string());
302                    accumulator
303                });
304
305        let separator = |output: &mut String| {
306            if !output.is_empty() {
307                output.push_str("\n\n");
308            }
309        };
310
311        if !types.is_empty() {
312            output.push_str(";; Types");
313            output.push_str(&types);
314        }
315
316        separator(&mut output);
317
318        if !imports.is_empty() {
319            output.push_str(";; Imports");
320            output.push_str(&imports);
321        }
322
323        separator(&mut output);
324
325        if !adapters.is_empty() {
326            output.push_str(";; Adapters");
327            output.push_str(&adapters);
328        }
329
330        separator(&mut output);
331
332        if !exports.is_empty() {
333            output.push_str(";; Exports");
334            output.push_str(&exports);
335        }
336
337        separator(&mut output);
338
339        if !implementations.is_empty() {
340            output.push_str(";; Implementations");
341            output.push_str(&implementations);
342        }
343
344        output
345    }
346}
347
348#[cfg(test)]
349mod tests {
350    use super::*;
351
352    #[test]
353    fn test_interface_types() {
354        let inputs: Vec<String> = vec![
355            (&InterfaceType::S8).to_string(),
356            (&InterfaceType::S16).to_string(),
357            (&InterfaceType::S32).to_string(),
358            (&InterfaceType::S64).to_string(),
359            (&InterfaceType::U8).to_string(),
360            (&InterfaceType::U16).to_string(),
361            (&InterfaceType::U32).to_string(),
362            (&InterfaceType::U64).to_string(),
363            (&InterfaceType::F32).to_string(),
364            (&InterfaceType::F64).to_string(),
365            (&InterfaceType::String).to_string(),
366            (&InterfaceType::Anyref).to_string(),
367            (&InterfaceType::I32).to_string(),
368            (&InterfaceType::I64).to_string(),
369            (&InterfaceType::Record(RecordType {
370                fields: vec1![InterfaceType::String],
371            }))
372                .to_string(),
373        ];
374        let outputs = vec![
375            "s8",
376            "s16",
377            "s32",
378            "s64",
379            "u8",
380            "u16",
381            "u32",
382            "u64",
383            "f32",
384            "f64",
385            "string",
386            "anyref",
387            "i32",
388            "i64",
389            "record (field string)",
390        ];
391
392        assert_eq!(inputs, outputs);
393    }
394
395    #[test]
396    fn test_record_type() {
397        let inputs = vec![
398            (&RecordType {
399                fields: vec1![InterfaceType::String],
400            })
401                .to_string(),
402            (&RecordType {
403                fields: vec1![InterfaceType::String, InterfaceType::I32],
404            })
405                .to_string(),
406            (&RecordType {
407                fields: vec1![
408                    InterfaceType::String,
409                    InterfaceType::Record(RecordType {
410                        fields: vec1![InterfaceType::I32, InterfaceType::I32],
411                    }),
412                    InterfaceType::F64,
413                ],
414            })
415                .to_string(),
416        ];
417        let outputs = vec![
418            "record (field string)",
419            "record (field string) (field i32)",
420            "record (field string) (field record (field i32) (field i32)) (field f64)",
421        ];
422
423        assert_eq!(inputs, outputs);
424    }
425
426    #[test]
427    fn test_instructions() {
428        let inputs: Vec<String> = vec![
429            (&Instruction::ArgumentGet { index: 7 }).to_string(),
430            (&Instruction::CallCore { function_index: 7 }).to_string(),
431            (&Instruction::S8FromI32).to_string(),
432            (&Instruction::S8FromI64).to_string(),
433            (&Instruction::S16FromI32).to_string(),
434            (&Instruction::S16FromI64).to_string(),
435            (&Instruction::S32FromI32).to_string(),
436            (&Instruction::S32FromI64).to_string(),
437            (&Instruction::S64FromI32).to_string(),
438            (&Instruction::S64FromI64).to_string(),
439            (&Instruction::I32FromS8).to_string(),
440            (&Instruction::I32FromS16).to_string(),
441            (&Instruction::I32FromS32).to_string(),
442            (&Instruction::I32FromS64).to_string(),
443            (&Instruction::I64FromS8).to_string(),
444            (&Instruction::I64FromS16).to_string(),
445            (&Instruction::I64FromS32).to_string(),
446            (&Instruction::I64FromS64).to_string(),
447            (&Instruction::U8FromI32).to_string(),
448            (&Instruction::U8FromI64).to_string(),
449            (&Instruction::U16FromI32).to_string(),
450            (&Instruction::U16FromI64).to_string(),
451            (&Instruction::U32FromI32).to_string(),
452            (&Instruction::U32FromI64).to_string(),
453            (&Instruction::U64FromI32).to_string(),
454            (&Instruction::U64FromI64).to_string(),
455            (&Instruction::I32FromU8).to_string(),
456            (&Instruction::I32FromU16).to_string(),
457            (&Instruction::I32FromU32).to_string(),
458            (&Instruction::I32FromU64).to_string(),
459            (&Instruction::I64FromU8).to_string(),
460            (&Instruction::I64FromU16).to_string(),
461            (&Instruction::I64FromU32).to_string(),
462            (&Instruction::I64FromU64).to_string(),
463            (&Instruction::StringLiftMemory).to_string(),
464            (&Instruction::StringLowerMemory).to_string(),
465            (&Instruction::StringSize).to_string(),
466            (&Instruction::RecordLift { type_index: 42 }).to_string(),
467            (&Instruction::RecordLower { type_index: 42 }).to_string(),
468        ];
469        let outputs = vec![
470            "arg.get 7",
471            "call-core 7",
472            "s8.from_i32",
473            "s8.from_i64",
474            "s16.from_i32",
475            "s16.from_i64",
476            "s32.from_i32",
477            "s32.from_i64",
478            "s64.from_i32",
479            "s64.from_i64",
480            "i32.from_s8",
481            "i32.from_s16",
482            "i32.from_s32",
483            "i32.from_s64",
484            "i64.from_s8",
485            "i64.from_s16",
486            "i64.from_s32",
487            "i64.from_s64",
488            "u8.from_i32",
489            "u8.from_i64",
490            "u16.from_i32",
491            "u16.from_i64",
492            "u32.from_i32",
493            "u32.from_i64",
494            "u64.from_i32",
495            "u64.from_i64",
496            "i32.from_u8",
497            "i32.from_u16",
498            "i32.from_u32",
499            "i32.from_u64",
500            "i64.from_u8",
501            "i64.from_u16",
502            "i64.from_u32",
503            "i64.from_u64",
504            "string.lift_memory",
505            "string.lower_memory",
506            "string.size",
507            "record.lift 42",
508            "record.lower 42",
509        ];
510
511        assert_eq!(inputs, outputs);
512    }
513
514    #[test]
515    fn test_types() {
516        let inputs: Vec<String> = vec![
517            (&Type::Function {
518                inputs: vec![InterfaceType::I32, InterfaceType::F32],
519                outputs: vec![InterfaceType::I32],
520            })
521                .to_string(),
522            (&Type::Function {
523                inputs: vec![InterfaceType::I32],
524                outputs: vec![],
525            })
526                .to_string(),
527            (&Type::Function {
528                inputs: vec![],
529                outputs: vec![InterfaceType::I32],
530            })
531                .to_string(),
532            (&Type::Function {
533                inputs: vec![],
534                outputs: vec![],
535            })
536                .to_string(),
537            (&Type::Record(RecordType {
538                fields: vec1![InterfaceType::String, InterfaceType::I32],
539            }))
540                .to_string(),
541        ];
542        let outputs = vec![
543            r#"(@interface type (func
544  (param i32 f32)
545  (result i32)))"#,
546            r#"(@interface type (func
547  (param i32)))"#,
548            r#"(@interface type (func
549  (result i32)))"#,
550            r#"(@interface type (func))"#,
551            r#"(@interface type (record (field string) (field i32)))"#,
552        ];
553
554        assert_eq!(inputs, outputs);
555    }
556
557    #[test]
558    fn test_exports() {
559        let input = (&Export {
560            name: "foo",
561            function_type: 0,
562        })
563            .to_string();
564        let output = r#"(@interface export "foo" (func 0))"#;
565
566        assert_eq!(input, output);
567    }
568
569    #[test]
570    fn test_imports() {
571        let input = (&Import {
572            namespace: "ns",
573            name: "foo",
574            signature_type: 0,
575        })
576            .to_string();
577        let output = r#"(@interface import "ns" "foo" (func (type 0)))"#;
578
579        assert_eq!(input, output);
580    }
581
582    #[test]
583    fn test_adapter() {
584        let input = (&Adapter {
585            function_type: 0,
586            instructions: vec![Instruction::ArgumentGet { index: 42 }],
587        })
588            .to_string();
589        let output = r#"(@interface func (type 0)
590  arg.get 42)"#;
591
592        assert_eq!(input, output);
593    }
594
595    #[test]
596    fn test_interfaces() {
597        let input: String = (&Interfaces {
598            types: vec![Type::Function {
599                inputs: vec![InterfaceType::I32],
600                outputs: vec![InterfaceType::S8],
601            }],
602            imports: vec![Import {
603                namespace: "ns",
604                name: "foo",
605                signature_type: 0,
606            }],
607            adapters: vec![Adapter {
608                function_type: 0,
609                instructions: vec![Instruction::ArgumentGet { index: 42 }],
610            }],
611            exports: vec![Export {
612                name: "bar",
613                function_type: 0,
614            }],
615            implementations: vec![Implementation {
616                core_function_type: 0,
617                adapter_function_type: 1,
618            }],
619        })
620            .to_string();
621        let output = r#";; Types
622(@interface type (func
623  (param i32)
624  (result s8)))
625
626;; Imports
627(@interface import "ns" "foo" (func (type 0)))
628
629;; Adapters
630(@interface func (type 0)
631  arg.get 42)
632
633;; Exports
634(@interface export "bar" (func 0))
635
636;; Implementations
637(@interface implement (func 0) (func 1))"#;
638
639        assert_eq!(input, output);
640    }
641}