1use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId, ValType};
2use alloc::vec::Vec;
3
4/// An encoder for the table section.
5///
6/// Table sections are only supported for modules.
7///
8/// # Example
9///
10/// ```
11/// use wasm_encoder::{Module, TableSection, TableType, RefType};
12///
13/// let mut tables = TableSection::new();
14/// tables.table(TableType {
15/// element_type: RefType::FUNCREF,
16/// minimum: 128,
17/// maximum: None,
18/// table64: false,
19/// shared: false,
20/// });
21///
22/// let mut module = Module::new();
23/// module.section(&tables);
24///
25/// let wasm_bytes = module.finish();
26/// ```
27#[derive(Clone, Default, Debug)]
28pub struct TableSection {
29 bytes: Vec<u8>,
30 num_added: u32,
31}
32
33impl TableSection {
34 /// Construct a new table section encoder.
35 pub fn new() -> Self {
36 Self::default()
37 }
38
39 /// The number of tables in the section.
40 pub fn len(&self) -> u32 {
41 self.num_added
42 }
43
44 /// Determines if the section is empty.
45 pub fn is_empty(&self) -> bool {
46 self.num_added == 0
47 }
48
49 /// Define a table.
50 pub fn table(&mut self, table_type: TableType) -> &mut Self {
51 table_type.encode(&mut self.bytes);
52 self.num_added += 1;
53 self
54 }
55
56 /// Define a table with an explicit initialization expression.
57 ///
58 /// Note that this is part of the function-references proposal.
59 pub fn table_with_init(&mut self, table_type: TableType, init: &ConstExpr) -> &mut Self {
60 self.bytes.push(0x40);
61 self.bytes.push(0x00);
62 table_type.encode(&mut self.bytes);
63 init.encode(&mut self.bytes);
64 self.num_added += 1;
65 self
66 }
67}
68
69impl Encode for TableSection {
70 fn encode(&self, sink: &mut Vec<u8>) {
71 encode_section(sink, self.num_added, &self.bytes);
72 }
73}
74
75impl Section for TableSection {
76 fn id(&self) -> u8 {
77 SectionId::Table.into()
78 }
79}
80
81/// A table's type.
82#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
83pub struct TableType {
84 /// The table's element type.
85 pub element_type: RefType,
86 /// Whether or not this is a 64-bit table.
87 pub table64: bool,
88 /// Minimum size, in elements, of this table
89 pub minimum: u64,
90 /// Maximum size, in elements, of this table
91 pub maximum: Option<u64>,
92 /// Whether this table is shared or not.
93 ///
94 /// This is included the shared-everything-threads proposal.
95 pub shared: bool,
96}
97
98impl TableType {
99 /// Returns the type used to index this table.
100 pub fn index_type(&self) -> ValType {
101 if self.table64 {
102 ValType::I64
103 } else {
104 ValType::I32
105 }
106 }
107}
108
109impl Encode for TableType {
110 fn encode(&self, sink: &mut Vec<u8>) {
111 let mut flags: u8 = 0;
112 if self.maximum.is_some() {
113 flags |= 0b001;
114 }
115 if self.shared {
116 flags |= 0b010;
117 }
118 if self.table64 {
119 flags |= 0b100;
120 }
121
122 self.element_type.encode(sink);
123 sink.push(flags);
124 self.minimum.encode(sink);
125
126 if let Some(max: u64) = self.maximum {
127 max.encode(sink);
128 }
129 }
130}
131