1#![doc = include_str!("readme.md")]
2
3use gaia_types::{GaiaError, Result};
4use std::{collections::HashMap, fmt};
5
6#[derive(Debug, Clone)]
10pub struct WasiProgram {
11 pub program_type: WasiProgramType,
13 pub name: Option<String>,
15 pub function_types: Vec<WasiFunctionType>,
17 pub functions: Vec<WasiFunction>,
19 pub exports: Vec<WasiExport>,
21 pub imports: Vec<WasiImport>,
23 pub memories: Vec<WasiMemory>,
25 pub tables: Vec<WasiTable>,
27 pub globals: Vec<WasiGlobal>,
29 pub custom_sections: Vec<WasiCustomSection>,
31 pub start_function: Option<u32>,
33 pub component_items: Vec<WasiComponentItem>,
35 pub core_modules: Vec<WasiCoreModule>,
37 pub instances: Vec<WasiInstance>,
39 pub aliases: Vec<WasiAlias>,
41 pub symbol_table: HashMap<String, WasiSymbol>,
43}
44
45#[derive(Copy, Clone, Debug, Default)]
46pub struct WasmInfo {
47 pub magic_head: [u8; 4],
48}
49
50#[derive(Debug, Clone, Copy, PartialEq)]
52pub enum WasiProgramType {
53 Component,
55 CoreModule,
57}
58
59#[derive(Debug, Clone)]
61pub enum WasiComponentItem {
62 Type(WasiTypeDefinition),
64 Alias(WasiAlias),
66 Instance(WasiInstance),
68 CoreFunc(WasiCoreFunc),
70 CoreInstance(WasiCoreInstance),
72}
73
74#[derive(Debug, Clone)]
76pub struct WasiCoreModule {
77 pub name: Option<String>,
79 pub index: u32,
81 pub function_types: Vec<WasiFunctionType>,
83 pub functions: Vec<WasiFunction>,
85 pub exports: Vec<WasiExport>,
87 pub imports: Vec<WasiImport>,
89 pub memories: Vec<WasiMemory>,
91 pub tables: Vec<WasiTable>,
93 pub globals: Vec<WasiGlobal>,
95 pub data_segments: Vec<WasiDataSegment>,
97 pub element_segments: Vec<WasiElementSegment>,
99 pub start_function: Option<u32>,
101}
102
103#[derive(Debug, Clone)]
105pub struct WasiInstance {
106 pub name: Option<String>,
108 pub index: u32,
110 pub instantiate_target: String,
112 pub args: Vec<WasiInstanceArg>,
114 pub instance_type: WasiInstanceType,
116}
117
118#[derive(Debug, Clone)]
120pub enum WasiInstanceType {
121 CoreModule,
123 Component,
125}
126
127#[derive(Debug, Clone)]
129pub struct WasiInstanceArg {
130 pub name: String,
132 pub value: String,
134}
135
136#[derive(Debug, Clone)]
138pub struct WasiAlias {
139 pub name: Option<String>,
141 pub target: WasiAliasTarget,
143}
144
145#[derive(Debug, Clone)]
147pub enum WasiAliasTarget {
148 Outer {
150 outer_index: u32,
152 item_index: u32,
154 },
155 Core {
157 core_type: WasiCoreType,
159 item_index: u32,
161 },
162 Export {
164 instance: String,
166 name: String,
168 },
169 CoreExport {
171 instance: String,
173 name: String,
175 },
176}
177
178#[derive(Debug, Clone, Copy)]
180pub enum WasiCoreType {
181 Module,
182 Func,
183 Table,
184 Memory,
185 Global,
186}
187
188#[derive(Debug, Clone)]
190pub struct WasiTypeDefinition {
191 pub name: Option<String>,
193 pub index: u32,
195 pub type_content: WasiType,
197}
198
199#[derive(Debug, Clone)]
201pub enum WasiType {
202 Func(WasiFunctionType),
204 Interface(String),
206 Instance(String),
208 Resource(WasiResourceType),
210 Record(Vec<WasiRecordField>),
212 Variant(Vec<WasiVariantCase>),
214 Enum(Vec<String>),
216 Union(Vec<WasiType>),
218 Option(Box<WasiType>),
220 List(Box<WasiType>),
222 Tuple(Vec<WasiType>),
224 Flags(Vec<String>),
226 Future(Option<Box<WasiType>>),
228 Stream(Option<Box<WasiType>>),
230 Primitive(WasiPrimitiveType),
232}
233
234#[derive(Debug, Clone)]
236pub struct WasiResourceType {
237 pub name: String,
239 pub methods: Vec<WasiResourceMethod>,
241}
242
243#[derive(Debug, Clone)]
245pub struct WasiResourceMethod {
246 pub name: String,
248 pub method_type: WasiFunctionType,
250}
251
252#[derive(Debug, Clone)]
254pub struct WasiRecordField {
255 pub name: String,
257 pub field_type: WasiType,
259}
260
261#[derive(Debug, Clone)]
263pub struct WasiVariantCase {
264 pub name: String,
266 pub case_type: Option<WasiType>,
268}
269
270#[derive(Debug, Clone, Copy)]
272pub enum WasiPrimitiveType {
273 Bool,
274 S8,
275 S16,
276 S32,
277 S64,
278 U8,
279 U16,
280 U32,
281 U64,
282 F32,
283 F64,
284 Char,
285 String,
286}
287
288#[derive(Debug, Clone)]
290pub struct WasiCoreFunc {
291 pub name: Option<String>,
293 pub index: u32,
295 pub func_type: WasiFunctionType,
297 pub canon: Option<WasiCanonicalOperation>,
299}
300
301#[derive(Debug, Clone)]
303pub enum WasiCanonicalOperation {
304 Lower {
306 func: String,
308 options: Vec<WasiCanonOption>,
310 },
311 Lift {
313 func: String,
315 options: Vec<WasiCanonOption>,
317 },
318 ResourceNew(String),
320 ResourceDrop(String),
322 ResourceRep(String),
324}
325
326#[derive(Debug, Clone)]
328pub enum WasiCanonOption {
329 StringEncoding(String),
331 Memory(String),
333 Realloc(String),
335 Async,
337 Callback(String),
339}
340
341#[derive(Debug, Clone)]
343pub struct WasiCoreInstance {
344 pub name: Option<String>,
346 pub index: u32,
348 pub instantiate_target: String,
350 pub args: Vec<WasiInstanceArg>,
352}
353
354#[derive(Debug, Clone)]
356pub struct WasiDataSegment {
357 pub name: Option<String>,
359 pub memory_index: Option<u32>,
361 pub offset: Vec<WasiInstruction>,
363 pub data: Vec<u8>,
365}
366
367#[derive(Debug, Clone)]
369pub struct WasiElementSegment {
370 pub name: Option<String>,
372 pub table_index: Option<u32>,
374 pub offset: Vec<WasiInstruction>,
376 pub elements: Vec<u32>,
378}
379
380#[derive(Debug, Clone)]
382pub struct WasiSymbol {
383 pub name: String,
385 pub symbol_type: WasiSymbolType,
387 pub index: u32,
389}
390
391#[derive(Debug, Clone)]
393pub enum WasiSymbolType {
394 Function,
395 Type,
396 Memory,
397 Table,
398 Global,
399 Instance,
400 Module,
401 Component,
402}
403
404#[derive(Debug, Clone, PartialEq)]
406pub struct WasiFunctionType {
407 pub params: Vec<WasmValueType>,
409 pub results: Vec<WasmValueType>,
411}
412
413#[derive(Debug, Clone, Copy, PartialEq)]
415pub enum WasmValueType {
416 I32,
417 I64,
418 F32,
419 F64,
420 V128,
421 Funcref,
422 Externref,
423}
424
425impl TryFrom<u8> for WasmValueType {
426 type Error = GaiaError;
427
428 fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
429 match value {
430 0x7F => Ok(WasmValueType::I32),
431 0x7E => Ok(WasmValueType::I64),
432 0x7D => Ok(WasmValueType::F32),
433 0x7C => Ok(WasmValueType::F64),
434 0x7B => Ok(WasmValueType::V128),
435 0x70 => Ok(WasmValueType::Funcref),
436 0x6F => Ok(WasmValueType::Externref),
437 _ => Err(GaiaError::invalid_data(&format!("Unknown value type: 0x{:02X}", value))),
438 }
439 }
440}
441
442impl fmt::Display for WasmValueType {
443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444 match self {
445 WasmValueType::I32 => write!(f, "i32"),
446 WasmValueType::I64 => write!(f, "i64"),
447 WasmValueType::F32 => write!(f, "f32"),
448 WasmValueType::F64 => write!(f, "f64"),
449 WasmValueType::V128 => write!(f, "v128"),
450 WasmValueType::Funcref => write!(f, "funcref"),
451 WasmValueType::Externref => write!(f, "externref"),
452 }
453 }
454}
455
456#[derive(Debug, Clone)]
458pub struct WasiFunction {
459 pub type_index: u32,
461 pub locals: Vec<WasmLocal>,
463 pub body: Vec<WasiInstruction>,
465}
466
467#[derive(Copy, Debug, Clone)]
469pub struct WasmLocal {
470 pub count: u32,
472 pub value_type: WasmValueType,
474}
475
476#[derive(Copy, Debug, Clone)]
478pub enum WasiInstruction {
479 Nop,
481 Unreachable,
483 Block {
485 block_type: Option<WasmValueType>,
486 },
487 Loop {
489 block_type: Option<WasmValueType>,
490 },
491 If {
493 block_type: Option<WasmValueType>,
494 },
495 Else,
497 End,
499 Br {
501 label_index: u32,
502 },
503 BrIf {
505 label_index: u32,
506 },
507 Return,
509 Call {
511 function_index: u32,
512 },
513 Drop,
515 Select,
517 LocalGet {
519 local_index: u32,
520 },
521 LocalSet {
523 local_index: u32,
524 },
525 I32Load {
527 offset: u32,
528 align: u32,
529 },
530 I64Load {
531 offset: u32,
532 align: u32,
533 },
534 F32Load {
535 offset: u32,
536 align: u32,
537 },
538 F64Load {
539 offset: u32,
540 align: u32,
541 },
542 I32Store {
544 offset: u32,
545 align: u32,
546 },
547 I64Store {
548 offset: u32,
549 align: u32,
550 },
551 F32Store {
552 offset: u32,
553 align: u32,
554 },
555 F64Store {
556 offset: u32,
557 align: u32,
558 },
559 StructNew {
561 type_index: u32,
562 },
563 StructGet {
564 type_index: u32,
565 field_index: u32,
566 },
567 StructSet {
568 type_index: u32,
569 field_index: u32,
570 },
571 I32Const {
573 value: i32,
574 },
575 I64Const {
576 value: i64,
577 },
578 F32Const {
579 value: f32,
580 },
581 F64Const {
582 value: f64,
583 },
584 I32Add,
586 I32Sub,
587 I32Mul,
588 I32DivS,
589 I32DivU,
590 I32RemS,
591 I32RemU,
592 I32And,
593 I32Or,
594 I32Xor,
595 I32Shl,
596 I32ShrS,
597 I32ShrU,
598 I32Rotl,
599 I32Rotr,
600 I32Eqz,
602 I32Eq,
603 I32Ne,
604 I32LtS,
605 I32LtU,
606 I32GtS,
607 I32GtU,
608 I32LeS,
609 I32LeU,
610 I32GeS,
611 I32GeU,
612 TaskBackpressure,
614 TaskReturn,
615 TaskWait,
616 TaskPoll,
617 TaskYield,
618 ErrorContextNew,
620 ErrorContextDebugMessage,
621}
622
623#[derive(Debug, Clone)]
625pub struct WasiExport {
626 pub name: String,
628 pub export_type: WasmExportType,
630}
631
632#[derive(Copy, Debug, Clone)]
634pub enum WasmExportType {
635 Function { function_index: u32 },
636 Table { table_index: u32 },
637 Memory { memory_index: u32 },
638 Global { global_index: u32 },
639}
640
641impl WasmExportType {
642 pub fn function_index(&self) -> Option<u32> {
643 match self {
644 WasmExportType::Function { function_index } => Some(*function_index),
645 _ => None,
646 }
647 }
648}
649
650#[derive(Debug, Clone)]
652pub struct WasiImport {
653 pub module: String,
655 pub field: String,
657 pub import_type: WasmImportType,
659}
660
661#[derive(Copy, Debug, Clone)]
663pub enum WasmImportType {
664 Function { type_index: u32 },
665 Table { table_type: WasmTableType },
666 Memory { memory_type: WasmMemoryType },
667 Global { global_type: WasmGlobalType },
668}
669
670#[derive(Copy, Debug, Clone)]
672pub struct WasiMemory {
673 pub memory_type: WasmMemoryType,
674}
675
676#[derive(Copy, Debug, Clone)]
678pub struct WasmMemoryType {
679 pub min: u32,
681 pub max: Option<u32>,
683}
684
685#[derive(Copy, Debug, Clone)]
687pub struct WasiTable {
688 pub table_type: WasmTableType,
689}
690
691#[derive(Copy, Debug, Clone)]
693pub struct WasmTableType {
694 pub element_type: WasmReferenceType,
696 pub min: u32,
698 pub max: Option<u32>,
700}
701
702#[derive(Copy, Debug, Clone)]
704pub enum WasmReferenceType {
705 FuncRef,
706 ExternRef,
707}
708
709#[derive(Debug, Clone)]
711pub struct WasiGlobal {
712 pub global_type: WasmGlobalType,
713 pub init_expr: Vec<WasiInstruction>,
714}
715
716#[derive(Copy, Debug, Clone)]
718pub struct WasmGlobalType {
719 pub value_type: WasmValueType,
720 pub mutable: bool,
721}
722
723#[derive(Debug, Clone)]
725pub struct WasiCustomSection {
726 pub name: String,
728 pub data: Vec<u8>,
730}
731
732impl WasiProgram {
733 pub fn new(program_type: WasiProgramType) -> Self {
735 Self {
736 program_type,
737 name: None,
738 function_types: Vec::new(),
739 functions: Vec::new(),
740 exports: Vec::new(),
741 imports: Vec::new(),
742 memories: Vec::new(),
743 tables: Vec::new(),
744 globals: Vec::new(),
745 custom_sections: Vec::new(),
746 start_function: None,
747 component_items: Vec::new(),
748 core_modules: Vec::new(),
749 instances: Vec::new(),
750 aliases: Vec::new(),
751 symbol_table: HashMap::new(),
752 }
753 }
754
755 pub fn new_component() -> Self {
757 Self::new(WasiProgramType::Component)
758 }
759
760 pub fn new_core_module() -> Self {
762 Self::new(WasiProgramType::CoreModule)
763 }
764
765 pub fn add_function_type(&mut self, func_type: WasiFunctionType) -> u32 {
767 for (index, existing_type) in self.function_types.iter().enumerate() {
769 if existing_type == &func_type {
770 return index as u32;
771 }
772 }
773
774 let index = self.function_types.len() as u32;
775 self.function_types.push(func_type);
776 index
777 }
778
779 pub fn add_function(&mut self, function: WasiFunction) -> u32 {
781 let index = self.functions.len() as u32;
782 self.functions.push(function);
783 index
784 }
785
786 pub fn add_export(&mut self, export: WasiExport) {
788 self.exports.push(export);
789 }
790
791 pub fn add_import(&mut self, import: WasiImport) {
793 self.imports.push(import);
794 }
795
796 pub fn add_memory(&mut self, memory: WasiMemory) -> u32 {
798 let index = self.memories.len() as u32;
799 self.memories.push(memory);
800 index
801 }
802
803 pub fn add_table(&mut self, table: WasiTable) -> u32 {
805 let index = self.tables.len() as u32;
806 self.tables.push(table);
807 index
808 }
809
810 pub fn add_global(&mut self, global: WasiGlobal) -> u32 {
812 let index = self.globals.len() as u32;
813 self.globals.push(global);
814 index
815 }
816
817 pub fn add_core_module(&mut self, core_module: WasiCoreModule) -> u32 {
819 let index = self.core_modules.len() as u32;
820 self.core_modules.push(core_module);
821 index
822 }
823
824 pub fn add_instance(&mut self, instance: WasiInstance) -> u32 {
826 let index = self.instances.len() as u32;
827 self.instances.push(instance);
828 index
829 }
830
831 pub fn add_alias(&mut self, alias: WasiAlias) {
833 self.aliases.push(alias);
834 }
835
836 pub fn add_symbol(&mut self, name: String, symbol_type: WasiSymbolType, index: u32) {
838 let symbol = WasiSymbol { name: name.clone(), symbol_type, index };
839 self.symbol_table.insert(name, symbol);
840 }
841
842 pub fn find_symbol(&self, name: &str) -> Option<&WasiSymbol> {
844 self.symbol_table.get(name)
845 }
846
847 pub fn validate(&self) -> Result<()> {
849 for function in &self.functions {
851 if function.type_index as usize >= self.function_types.len() {
852 return Err(GaiaError::custom_error(format!(
853 "函数类型索引 {} 超出范围,最大索引为 {}",
854 function.type_index,
855 self.function_types.len().saturating_sub(1)
856 )));
857 }
858 }
859
860 for export in &self.exports {
862 match &export.export_type {
863 WasmExportType::Function { function_index } => {
864 let total_functions =
865 self.imports.iter().filter(|imp| matches!(imp.import_type, WasmImportType::Function { .. })).count()
866 + self.functions.len();
867
868 if *function_index as usize >= total_functions {
869 return Err(GaiaError::custom_error(format!(
870 "导出函数索引 {} 超出范围,最大索引为 {}",
871 function_index,
872 total_functions.saturating_sub(1)
873 )));
874 }
875 }
876 _ => {} }
878 }
879
880 Ok(())
881 }
882
883 #[cfg(feature = "wat")]
885 pub fn to_wat(&self) -> gaia_types::Result<oak_wat::ast::WatRoot> {
886 use oak_wat::ast::{
887 WatExport, WatFunc, WatImport, WatInstruction, WatItem, WatLocal, WatModule, WatModuleField, WatParam, WatResult,
888 WatRoot, WatTypeKind,
889 };
890
891 let mut module_items = Vec::new();
892
893 for (i, import) in self.imports.iter().enumerate() {
895 let kind = match import.import_type {
896 WasmImportType::Function { .. } => "func",
897 WasmImportType::Table { .. } => "table",
898 WasmImportType::Memory { .. } => "memory",
899 WasmImportType::Global { .. } => "global",
900 };
901 let index = match import.import_type {
902 WasmImportType::Function { type_index } => type_index,
903 _ => 0, };
905
906 module_items.push(WatModuleField::Import(WatImport {
907 module: import.module.clone(),
908 field: import.field.clone(),
909 kind: kind.to_string(),
910 index,
911 }));
912 }
913
914 for (i, func) in self.functions.iter().enumerate() {
916 let func_type = &self.function_types[func.type_index as usize];
917
918 let mut params = Vec::new();
919 for (j, param) in func_type.params.iter().enumerate() {
920 params.push(WatParam {
921 name: Some(format!("$p{}", j)),
922 ty: match param {
923 WasmValueType::I32 => WatTypeKind::I32,
924 WasmValueType::I64 => WatTypeKind::I64,
925 WasmValueType::F32 => WatTypeKind::F32,
926 WasmValueType::F64 => WatTypeKind::F64,
927 _ => WatTypeKind::I32, },
929 });
930 }
931
932 let mut results = Vec::new();
933 for result in &func_type.results {
934 results.push(WatResult {
935 ty: match result {
936 WasmValueType::I32 => WatTypeKind::I32,
937 WasmValueType::I64 => WatTypeKind::I64,
938 WasmValueType::F32 => WatTypeKind::F32,
939 WasmValueType::F64 => WatTypeKind::F64,
940 _ => WatTypeKind::I32, },
942 });
943 }
944
945 let mut locals = Vec::new();
946 let mut local_idx = 0;
947 for local_group in &func.locals {
948 for _ in 0..local_group.count {
949 locals.push(WatLocal {
950 name: Some(format!("$l{}", local_idx)),
951 ty: match local_group.value_type {
952 WasmValueType::I32 => WatTypeKind::I32,
953 WasmValueType::I64 => WatTypeKind::I64,
954 WasmValueType::F32 => WatTypeKind::F32,
955 WasmValueType::F64 => WatTypeKind::F64,
956 _ => WatTypeKind::I32, },
958 });
959 local_idx += 1;
960 }
961 }
962
963 let mut body = Vec::new();
964 for instr in &func.body {
965 let instr_str = match instr {
966 WasiInstruction::Nop => "nop".to_string(),
967 WasiInstruction::Unreachable => "unreachable".to_string(),
968 WasiInstruction::Return => "return".to_string(),
969 WasiInstruction::Drop => "drop".to_string(),
970 WasiInstruction::Select => "select".to_string(),
971 WasiInstruction::I32Add => "i32.add".to_string(),
972 WasiInstruction::I32Sub => "i32.sub".to_string(),
973 WasiInstruction::I32Mul => "i32.mul".to_string(),
974 WasiInstruction::I32DivS => "i32.div_s".to_string(),
975 WasiInstruction::I32DivU => "i32.div_u".to_string(),
976 WasiInstruction::I32RemS => "i32.rem_s".to_string(),
977 WasiInstruction::I32RemU => "i32.rem_u".to_string(),
978 WasiInstruction::I32And => "i32.and".to_string(),
979 WasiInstruction::I32Or => "i32.or".to_string(),
980 WasiInstruction::I32Xor => "i32.xor".to_string(),
981 WasiInstruction::I32Shl => "i32.shl".to_string(),
982 WasiInstruction::I32ShrS => "i32.shr_s".to_string(),
983 WasiInstruction::I32ShrU => "i32.shr_u".to_string(),
984 WasiInstruction::I32Rotl => "i32.rotl".to_string(),
985 WasiInstruction::I32Rotr => "i32.rotr".to_string(),
986 WasiInstruction::I32Eqz => "i32.eqz".to_string(),
987 WasiInstruction::I32Eq => "i32.eq".to_string(),
988 WasiInstruction::I32Ne => "i32.ne".to_string(),
989 WasiInstruction::I32LtS => "i32.lt_s".to_string(),
990 WasiInstruction::I32LtU => "i32.lt_u".to_string(),
991 WasiInstruction::I32GtS => "i32.gt_s".to_string(),
992 WasiInstruction::I32GtU => "i32.gt_u".to_string(),
993 WasiInstruction::I32LeS => "i32.le_s".to_string(),
994 WasiInstruction::I32LeU => "i32.le_u".to_string(),
995 WasiInstruction::I32GeS => "i32.ge_s".to_string(),
996 WasiInstruction::I32GeU => "i32.ge_u".to_string(),
997 WasiInstruction::I32Load { offset, align } => format!("i32.load offset={} align={}", offset, align),
998 WasiInstruction::I64Load { offset, align } => format!("i64.load offset={} align={}", offset, align),
999 WasiInstruction::F32Load { offset, align } => format!("f32.load offset={} align={}", offset, align),
1000 WasiInstruction::F64Load { offset, align } => format!("f64.load offset={} align={}", offset, align),
1001 WasiInstruction::I32Store { offset, align } => format!("i32.store offset={} align={}", offset, align),
1002 WasiInstruction::I64Store { offset, align } => format!("i64.store offset={} align={}", offset, align),
1003 WasiInstruction::F32Store { offset, align } => format!("f32.store offset={} align={}", offset, align),
1004 WasiInstruction::F64Store { offset, align } => format!("f64.store offset={} align={}", offset, align),
1005 WasiInstruction::StructNew { type_index } => format!("struct.new {}", type_index),
1006 WasiInstruction::StructGet { type_index, field_index } => {
1007 format!("struct.get {} {}", type_index, field_index)
1008 }
1009 WasiInstruction::StructSet { type_index, field_index } => {
1010 format!("struct.set {} {}", type_index, field_index)
1011 }
1012 WasiInstruction::TaskBackpressure => "task.backpressure".to_string(),
1013 WasiInstruction::TaskReturn => "task.return".to_string(),
1014 WasiInstruction::TaskWait => "task.wait".to_string(),
1015 WasiInstruction::TaskPoll => "task.poll".to_string(),
1016 WasiInstruction::TaskYield => "task.yield".to_string(),
1017 WasiInstruction::ErrorContextNew => "error_context.new".to_string(),
1018 WasiInstruction::ErrorContextDebugMessage => "error_context.debug_message".to_string(),
1019 WasiInstruction::LocalGet { local_index } => format!("local.get {}", local_index),
1020 WasiInstruction::LocalSet { local_index } => format!("local.set {}", local_index),
1021 WasiInstruction::I32Const { value } => format!("i32.const {}", value),
1022 WasiInstruction::I64Const { value } => format!("i64.const {}", value),
1023 WasiInstruction::F32Const { value } => format!("f32.const {}", value),
1024 WasiInstruction::F64Const { value } => format!("f64.const {}", value),
1025 WasiInstruction::Call { function_index } => format!("call {}", function_index),
1026 WasiInstruction::Block { .. } => "block".to_string(),
1027 WasiInstruction::Loop { .. } => "loop".to_string(),
1028 WasiInstruction::If { .. } => "if".to_string(),
1029 WasiInstruction::Else => "else".to_string(),
1030 WasiInstruction::End => "end".to_string(),
1031 WasiInstruction::Br { label_index } => format!("br {}", label_index),
1032 WasiInstruction::BrIf { label_index } => format!("br_if {}", label_index),
1033 _ => format!(";; unknown instruction {:?}", instr),
1034 };
1035 body.push(WatInstruction { name: instr_str });
1036 }
1037
1038 module_items.push(WatModuleField::Func(WatFunc { name: Some(format!("$f{}", i)), params, results, locals, body }));
1039 }
1040
1041 for export in &self.exports {
1043 let (kind, index) = match export.export_type {
1044 WasmExportType::Function { function_index } => ("func", function_index),
1045 WasmExportType::Table { table_index } => ("table", table_index),
1046 WasmExportType::Memory { memory_index } => ("memory", memory_index),
1047 WasmExportType::Global { global_index } => ("global", global_index),
1048 };
1049 module_items.push(WatModuleField::Export(WatExport { name: export.name.clone(), kind: kind.to_string(), index }));
1050 }
1051
1052 let mut items = Vec::new();
1053 if self.program_type == WasiProgramType::CoreModule {
1054 let module = WatModule { name: self.name.clone(), items: module_items };
1055 items.push(WatItem::Module(module));
1056 }
1057
1058 Ok(WatRoot { items })
1059 }
1060
1061 pub fn to_wasm(&self) -> Result<Vec<u8>> {
1063 let mut writer = crate::formats::wasm::writer::WasmWriter::new(Vec::new());
1064 writer.write(self.clone()).result
1065 }
1066}
1067
1068impl Default for WasiProgram {
1069 fn default() -> Self {
1070 Self::new_core_module()
1071 }
1072}
1073
1074pub struct WasiProgramBuilder {
1076 program: WasiProgram,
1077}
1078
1079impl WasiProgramBuilder {
1080 pub fn new(program_type: WasiProgramType) -> Self {
1082 Self { program: WasiProgram::new(program_type) }
1083 }
1084
1085 pub fn with_name(mut self, name: impl Into<String>) -> Self {
1087 self.program.name = Some(name.into());
1088 self
1089 }
1090
1091 pub fn with_function_type(mut self, func_type: WasiFunctionType) -> Self {
1093 self.program.add_function_type(func_type);
1094 self
1095 }
1096
1097 pub fn with_function(mut self, function: WasiFunction) -> Self {
1099 self.program.add_function(function);
1100 self
1101 }
1102
1103 pub fn with_export(mut self, export: WasiExport) -> Self {
1105 self.program.add_export(export);
1106 self
1107 }
1108
1109 pub fn with_import(mut self, import: WasiImport) -> Self {
1111 self.program.add_import(import);
1112 self
1113 }
1114
1115 pub fn with_memory(mut self, memory: WasiMemory) -> Self {
1117 self.program.add_memory(memory);
1118 self
1119 }
1120
1121 pub fn with_table(mut self, table: WasiTable) -> Self {
1123 self.program.add_table(table);
1124 self
1125 }
1126
1127 pub fn with_global(mut self, global: WasiGlobal) -> Self {
1129 self.program.add_global(global);
1130 self
1131 }
1132
1133 pub fn with_custom_section(mut self, custom_section: WasiCustomSection) -> Self {
1135 self.program.custom_sections.push(custom_section);
1136 self
1137 }
1138
1139 pub fn with_start_function(mut self, start_function_index: u32) -> Self {
1141 self.program.start_function = Some(start_function_index);
1142 self
1143 }
1144
1145 pub fn with_component_item(mut self, item: WasiComponentItem) -> Self {
1147 self.program.component_items.push(item);
1148 self
1149 }
1150
1151 pub fn with_core_module(mut self, core_module: WasiCoreModule) -> Self {
1153 self.program.add_core_module(core_module);
1154 self
1155 }
1156
1157 pub fn with_instance(mut self, instance: WasiInstance) -> Self {
1159 self.program.add_instance(instance);
1160 self
1161 }
1162
1163 pub fn with_alias(mut self, alias: WasiAlias) -> Self {
1165 self.program.add_alias(alias);
1166 self
1167 }
1168
1169 pub fn with_symbol(mut self, name: impl Into<String>, symbol_type: WasiSymbolType, index: u32) -> Self {
1171 self.program.add_symbol(name.into(), symbol_type, index);
1172 self
1173 }
1174
1175 pub fn build(self) -> Result<WasiProgram> {
1177 self.program.validate().map(|_| self.program)
1178 }
1179}
1180
1181impl WasiProgram {
1182 pub fn builder(program_type: WasiProgramType) -> WasiProgramBuilder {
1184 WasiProgramBuilder::new(program_type)
1185 }
1186}