1use crate::{encode_section, encoding_size, ConstExpr, Encode, Section, SectionId};
2
3/// An encoder for the data section.
4///
5/// Data sections are only supported for modules.
6///
7/// # Example
8///
9/// ```
10/// use wasm_encoder::{
11/// ConstExpr, DataSection, Instruction, MemorySection, MemoryType,
12/// Module,
13/// };
14///
15/// let mut memory = MemorySection::new();
16/// memory.memory(MemoryType {
17/// minimum: 1,
18/// maximum: None,
19/// memory64: false,
20/// shared: false,
21/// page_size_log2: None,
22/// });
23///
24/// let mut data = DataSection::new();
25/// let memory_index = 0;
26/// let offset = ConstExpr::i32_const(42);
27/// let segment_data = b"hello";
28/// data.active(memory_index, &offset, segment_data.iter().copied());
29///
30/// let mut module = Module::new();
31/// module
32/// .section(&memory)
33/// .section(&data);
34///
35/// let wasm_bytes = module.finish();
36/// ```
37#[derive(Clone, Default, Debug)]
38pub struct DataSection {
39 bytes: Vec<u8>,
40 num_added: u32,
41}
42
43/// A segment in the data section.
44#[derive(Clone, Debug)]
45pub struct DataSegment<'a, D> {
46 /// This data segment's mode.
47 pub mode: DataSegmentMode<'a>,
48 /// This data segment's data.
49 pub data: D,
50}
51
52/// A data segment's mode.
53#[derive(Clone, Debug)]
54pub enum DataSegmentMode<'a> {
55 /// An active data segment.
56 Active {
57 /// The memory this segment applies to.
58 memory_index: u32,
59 /// The offset where this segment's data is initialized at.
60 offset: &'a ConstExpr,
61 },
62 /// A passive data segment.
63 ///
64 /// Passive data segments are part of the bulk memory proposal.
65 Passive,
66}
67
68impl DataSection {
69 /// Create a new data section encoder.
70 pub fn new() -> Self {
71 Self::default()
72 }
73
74 /// The number of data segments in the section.
75 pub fn len(&self) -> u32 {
76 self.num_added
77 }
78
79 /// Determines if the section is empty.
80 pub fn is_empty(&self) -> bool {
81 self.num_added == 0
82 }
83
84 /// Define a data segment.
85 pub fn segment<D>(&mut self, segment: DataSegment<D>) -> &mut Self
86 where
87 D: IntoIterator<Item = u8>,
88 D::IntoIter: ExactSizeIterator,
89 {
90 match segment.mode {
91 DataSegmentMode::Passive => {
92 self.bytes.push(0x01);
93 }
94 DataSegmentMode::Active {
95 memory_index: 0,
96 offset,
97 } => {
98 self.bytes.push(0x00);
99 offset.encode(&mut self.bytes);
100 }
101 DataSegmentMode::Active {
102 memory_index,
103 offset,
104 } => {
105 self.bytes.push(0x02);
106 memory_index.encode(&mut self.bytes);
107 offset.encode(&mut self.bytes);
108 }
109 }
110
111 let data = segment.data.into_iter();
112 data.len().encode(&mut self.bytes);
113 self.bytes.extend(data);
114
115 self.num_added += 1;
116 self
117 }
118
119 /// Define an active data segment.
120 pub fn active<D>(&mut self, memory_index: u32, offset: &ConstExpr, data: D) -> &mut Self
121 where
122 D: IntoIterator<Item = u8>,
123 D::IntoIter: ExactSizeIterator,
124 {
125 self.segment(DataSegment {
126 mode: DataSegmentMode::Active {
127 memory_index,
128 offset,
129 },
130 data,
131 })
132 }
133
134 /// Define a passive data segment.
135 ///
136 /// Passive data segments are part of the bulk memory proposal.
137 pub fn passive<D>(&mut self, data: D) -> &mut Self
138 where
139 D: IntoIterator<Item = u8>,
140 D::IntoIter: ExactSizeIterator,
141 {
142 self.segment(DataSegment {
143 mode: DataSegmentMode::Passive,
144 data,
145 })
146 }
147
148 /// Copy an already-encoded data segment into this data section.
149 pub fn raw(&mut self, already_encoded_data_segment: &[u8]) -> &mut Self {
150 self.bytes.extend_from_slice(already_encoded_data_segment);
151 self.num_added += 1;
152 self
153 }
154}
155
156impl Encode for DataSection {
157 fn encode(&self, sink: &mut Vec<u8>) {
158 encode_section(sink, self.num_added, &self.bytes);
159 }
160}
161
162impl Section for DataSection {
163 fn id(&self) -> u8 {
164 SectionId::Data.into()
165 }
166}
167
168/// An encoder for the data count section.
169#[derive(Clone, Copy, Debug)]
170pub struct DataCountSection {
171 /// The number of segments in the data section.
172 pub count: u32,
173}
174
175impl Encode for DataCountSection {
176 fn encode(&self, sink: &mut Vec<u8>) {
177 encoding_size(self.count).encode(sink);
178 self.count.encode(sink);
179 }
180}
181
182impl Section for DataCountSection {
183 fn id(&self) -> u8 {
184 SectionId::DataCount.into()
185 }
186}
187