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