parity_wasm/elements/
segment.rs

1use super::{CountedList, CountedListWriter, Deserialize, Error, InitExpr, Serialize, VarUint32};
2use crate::io;
3use alloc::vec::Vec;
4
5#[cfg(feature = "bulk")]
6const FLAG_MEMZERO: u32 = 0;
7#[cfg(feature = "bulk")]
8const FLAG_PASSIVE: u32 = 1;
9#[cfg(feature = "bulk")]
10const FLAG_MEM_NONZERO: u32 = 2;
11
12#[cfg(feature = "reduced-stack-buffer")]
13const VALUES_BUFFER_LENGTH: usize = 256;
14
15#[cfg(not(feature = "reduced-stack-buffer"))]
16const VALUES_BUFFER_LENGTH: usize = 16384;
17
18/// Entry in the element section.
19#[derive(Debug, Clone, PartialEq)]
20pub struct ElementSegment {
21	index: u32,
22	offset: Option<InitExpr>,
23	members: Vec<u32>,
24
25	#[cfg(feature = "bulk")]
26	passive: bool,
27}
28
29impl ElementSegment {
30	/// New element segment.
31	pub fn new(index: u32, offset: Option<InitExpr>, members: Vec<u32>) -> Self {
32		ElementSegment {
33			index,
34			offset,
35			members,
36
37			#[cfg(feature = "bulk")]
38			passive: false,
39		}
40	}
41
42	/// Sequence of function indices.
43	pub fn members(&self) -> &[u32] {
44		&self.members
45	}
46
47	/// Sequence of function indices (mutable)
48	pub fn members_mut(&mut self) -> &mut Vec<u32> {
49		&mut self.members
50	}
51
52	/// Table index (currently valid only value of `0`)
53	pub fn index(&self) -> u32 {
54		self.index
55	}
56
57	/// An i32 initializer expression that computes the offset at which to place the elements.
58	///
59	/// Note that this return `None` if the segment is `passive`.
60	pub fn offset(&self) -> &Option<InitExpr> {
61		&self.offset
62	}
63
64	/// An i32 initializer expression that computes the offset at which to place the elements (mutable)
65	///
66	/// Note that this return `None` if the segment is `passive`.
67	pub fn offset_mut(&mut self) -> &mut Option<InitExpr> {
68		&mut self.offset
69	}
70}
71
72#[cfg(feature = "bulk")]
73impl ElementSegment {
74	/// Whether or not this table segment is "passive"
75	pub fn passive(&self) -> bool {
76		self.passive
77	}
78
79	/// Whether or not this table segment is "passive"
80	pub fn passive_mut(&mut self) -> &mut bool {
81		&mut self.passive
82	}
83
84	/// Set whether or not this table segment is "passive"
85	pub fn set_passive(&mut self, passive: bool) {
86		self.passive = passive;
87	}
88}
89
90impl Deserialize for ElementSegment {
91	type Error = Error;
92
93	#[cfg(not(feature = "bulk"))]
94	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
95		let index: u32 = VarUint32::deserialize(reader)?.into();
96		let offset = InitExpr::deserialize(reader)?;
97		let members: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
98			.into_inner()
99			.into_iter()
100			.map(Into::into)
101			.collect();
102
103		Ok(ElementSegment { index, offset: Some(offset), members })
104	}
105
106	#[cfg(feature = "bulk")]
107	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
108		// This piece of data was treated as `index` [of the table], but was repurposed
109		// for flags in bulk-memory operations proposal.
110		let flags: u32 = VarUint32::deserialize(reader)?.into();
111		let index = if flags == FLAG_MEMZERO || flags == FLAG_PASSIVE {
112			0u32
113		} else if flags == FLAG_MEM_NONZERO {
114			VarUint32::deserialize(reader)?.into()
115		} else {
116			return Err(Error::InvalidSegmentFlags(flags))
117		};
118		let offset =
119			if flags == FLAG_PASSIVE { None } else { Some(InitExpr::deserialize(reader)?) };
120
121		let members: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
122			.into_inner()
123			.into_iter()
124			.map(Into::into)
125			.collect();
126
127		Ok(ElementSegment { index, offset, members, passive: flags == FLAG_PASSIVE })
128	}
129}
130
131impl Serialize for ElementSegment {
132	type Error = Error;
133
134	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
135		#[cfg(feature = "bulk")]
136		{
137			if self.passive {
138				VarUint32::from(FLAG_PASSIVE).serialize(writer)?;
139			} else if self.index != 0 {
140				VarUint32::from(FLAG_MEM_NONZERO).serialize(writer)?;
141				VarUint32::from(self.index).serialize(writer)?;
142			} else {
143				VarUint32::from(FLAG_MEMZERO).serialize(writer)?;
144			}
145		}
146		#[cfg(not(feature = "bulk"))]
147		VarUint32::from(self.index).serialize(writer)?;
148
149		if let Some(offset) = self.offset {
150			offset.serialize(writer)?;
151		}
152		let data = self.members;
153		let counted_list =
154			CountedListWriter::<VarUint32, _>(data.len(), data.into_iter().map(Into::into));
155		counted_list.serialize(writer)?;
156		Ok(())
157	}
158}
159
160/// Data segment definition.
161#[derive(Clone, Debug, PartialEq)]
162pub struct DataSegment {
163	index: u32,
164	offset: Option<InitExpr>,
165	value: Vec<u8>,
166
167	#[cfg(feature = "bulk")]
168	passive: bool,
169}
170
171impl DataSegment {
172	/// New data segments.
173	pub fn new(index: u32, offset: Option<InitExpr>, value: Vec<u8>) -> Self {
174		DataSegment {
175			index,
176			offset,
177			value,
178
179			#[cfg(feature = "bulk")]
180			passive: false,
181		}
182	}
183
184	/// Linear memory index (currently the only valid value is `0`).
185	pub fn index(&self) -> u32 {
186		self.index
187	}
188
189	/// An i32 initializer expression that computes the offset at which to place the data.
190	///
191	/// Note that this return `None` if the segment is `passive`.
192	pub fn offset(&self) -> &Option<InitExpr> {
193		&self.offset
194	}
195
196	/// An i32 initializer expression that computes the offset at which to place the data (mutable)
197	///
198	/// Note that this return `None` if the segment is `passive`.
199	pub fn offset_mut(&mut self) -> &mut Option<InitExpr> {
200		&mut self.offset
201	}
202
203	/// Initial value of the data segment.
204	pub fn value(&self) -> &[u8] {
205		&self.value
206	}
207
208	/// Initial value of the data segment (mutable).
209	pub fn value_mut(&mut self) -> &mut Vec<u8> {
210		&mut self.value
211	}
212}
213
214#[cfg(feature = "bulk")]
215impl DataSegment {
216	/// Whether or not this data segment is "passive".
217	pub fn passive(&self) -> bool {
218		self.passive
219	}
220
221	/// Whether or not this data segment is "passive" (mutable).
222	pub fn passive_mut(&mut self) -> &mut bool {
223		&mut self.passive
224	}
225
226	/// Set whether or not this table segment is "passive"
227	pub fn set_passive(&mut self, passive: bool) {
228		self.passive = passive;
229	}
230}
231
232impl Deserialize for DataSegment {
233	type Error = Error;
234
235	#[cfg(not(feature = "bulk"))]
236	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
237		let index = VarUint32::deserialize(reader)?;
238		let offset = InitExpr::deserialize(reader)?;
239		let value_len = u32::from(VarUint32::deserialize(reader)?) as usize;
240		let value = buffered_read!(VALUES_BUFFER_LENGTH, value_len, reader);
241
242		Ok(DataSegment { index: index.into(), offset: Some(offset), value })
243	}
244
245	#[cfg(feature = "bulk")]
246	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
247		let flags: u32 = VarUint32::deserialize(reader)?.into();
248		let index = if flags == FLAG_MEMZERO || flags == FLAG_PASSIVE {
249			0u32
250		} else if flags == FLAG_MEM_NONZERO {
251			VarUint32::deserialize(reader)?.into()
252		} else {
253			return Err(Error::InvalidSegmentFlags(flags))
254		};
255		let offset =
256			if flags == FLAG_PASSIVE { None } else { Some(InitExpr::deserialize(reader)?) };
257		let value_len = u32::from(VarUint32::deserialize(reader)?) as usize;
258		let value = buffered_read!(VALUES_BUFFER_LENGTH, value_len, reader);
259
260		Ok(DataSegment { index, offset, value, passive: flags == FLAG_PASSIVE })
261	}
262}
263
264impl Serialize for DataSegment {
265	type Error = Error;
266
267	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
268		#[cfg(feature = "bulk")]
269		{
270			if self.passive {
271				VarUint32::from(FLAG_PASSIVE).serialize(writer)?;
272			} else if self.index != 0 {
273				VarUint32::from(FLAG_MEM_NONZERO).serialize(writer)?;
274				VarUint32::from(self.index).serialize(writer)?;
275			} else {
276				VarUint32::from(FLAG_MEMZERO).serialize(writer)?;
277			}
278		}
279		#[cfg(not(feature = "bulk"))]
280		VarUint32::from(self.index).serialize(writer)?;
281
282		if let Some(offset) = self.offset {
283			offset.serialize(writer)?;
284		}
285
286		let value = self.value;
287		VarUint32::from(value.len()).serialize(writer)?;
288		writer.write(&value[..])?;
289		Ok(())
290	}
291}