1/* Copyright 2018 Mozilla Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#[cfg(feature = "simd")]
17mod simd;
18
19use crate::prelude::*;
20use crate::{limits::*, *};
21use core::fmt;
22use core::marker;
23use core::ops::Range;
24use core::str;
25
26pub(crate) const WASM_MAGIC_NUMBER: &[u8; 4] = b"\0asm";
27
28/// A binary reader for WebAssembly modules.
29#[derive(Debug, Clone)]
30pub struct BinaryReaderError {
31 // Wrap the actual error data in a `Box` so that the error is just one
32 // word. This means that we can continue returning small `Result`s in
33 // registers.
34 pub(crate) inner: Box<BinaryReaderErrorInner>,
35}
36
37#[derive(Debug, Clone)]
38pub(crate) struct BinaryReaderErrorInner {
39 pub(crate) message: String,
40 pub(crate) kind: BinaryReaderErrorKind,
41 pub(crate) offset: usize,
42 pub(crate) needed_hint: Option<usize>,
43}
44
45#[derive(Debug, Clone, Copy)]
46pub(crate) enum BinaryReaderErrorKind {
47 Custom,
48 Invalid,
49}
50
51/// The result for `BinaryReader` operations.
52pub type Result<T, E = BinaryReaderError> = core::result::Result<T, E>;
53
54#[cfg(feature = "std")]
55impl std::error::Error for BinaryReaderError {}
56
57#[cfg(all(not(feature = "std"), core_error))]
58impl core::error::Error for BinaryReaderError {}
59
60impl fmt::Display for BinaryReaderError {
61 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62 write!(
63 f,
64 "{} (at offset 0x{:x})",
65 self.inner.message, self.inner.offset
66 )
67 }
68}
69
70impl BinaryReaderError {
71 #[cold]
72 pub(crate) fn _new(kind: BinaryReaderErrorKind, message: String, offset: usize) -> Self {
73 BinaryReaderError {
74 inner: Box::new(BinaryReaderErrorInner {
75 kind,
76 message,
77 offset,
78 needed_hint: None,
79 }),
80 }
81 }
82
83 #[cold]
84 pub(crate) fn new(message: impl Into<String>, offset: usize) -> Self {
85 Self::_new(BinaryReaderErrorKind::Custom, message.into(), offset)
86 }
87
88 #[cold]
89 pub(crate) fn invalid(msg: &'static str, offset: usize) -> Self {
90 Self::_new(BinaryReaderErrorKind::Invalid, msg.into(), offset)
91 }
92
93 #[cold]
94 pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: usize) -> Self {
95 BinaryReaderError::new(args.to_string(), offset)
96 }
97
98 #[cold]
99 pub(crate) fn eof(offset: usize, needed_hint: usize) -> Self {
100 let mut err = BinaryReaderError::new("unexpected end-of-file", offset);
101 err.inner.needed_hint = Some(needed_hint);
102 err
103 }
104
105 pub(crate) fn kind(&mut self) -> BinaryReaderErrorKind {
106 self.inner.kind
107 }
108
109 /// Get this error's message.
110 pub fn message(&self) -> &str {
111 &self.inner.message
112 }
113
114 /// Get the offset within the Wasm binary where the error occurred.
115 pub fn offset(&self) -> usize {
116 self.inner.offset
117 }
118
119 #[cfg(all(feature = "validate", feature = "component-model"))]
120 pub(crate) fn add_context(&mut self, context: String) {
121 self.inner.message = format!("{context}\n{}", self.inner.message);
122 }
123
124 pub(crate) fn set_message(&mut self, message: &str) {
125 self.inner.message = message.to_string();
126 }
127}
128
129/// A binary reader of the WebAssembly structures and types.
130#[derive(Clone, Debug, Hash)]
131pub struct BinaryReader<'a> {
132 buffer: &'a [u8],
133 position: usize,
134 original_offset: usize,
135
136 // When the `features` feature is disabled then the `WasmFeatures` type
137 // still exists but this field is still omitted. When `features` is
138 // disabled then the only constructor of this type is `BinaryReader::new`
139 // which documents all known features being active. All known features
140 // being active isn't represented by `WasmFeatures` when the feature is
141 // disabled so the field is omitted here to prevent accidentally using the
142 // wrong listing of features.
143 //
144 // Feature accessors are defined by `foreach_wasm_feature!` below with a
145 // method-per-feature on `BinaryReader` which when the `features` feature
146 // is disabled returns `true` by default.
147 #[cfg(feature = "features")]
148 features: WasmFeatures,
149}
150
151impl<'a> BinaryReader<'a> {
152 /// Creates a new binary reader which will parse the `data` provided.
153 ///
154 /// The `original_offset` provided is used for byte offsets in errors that
155 /// are generated. That offset is added to the current position in `data`.
156 /// This can be helpful when `data` is just a window of a view into a larger
157 /// wasm binary perhaps not even entirely stored locally.
158 ///
159 /// The returned binary reader will have all features known to this crate
160 /// enabled. To reject binaries that aren't valid unless a certain feature
161 /// is enabled use the [`BinaryReader::new_features`] constructor instead.
162 pub fn new(data: &[u8], original_offset: usize) -> BinaryReader {
163 BinaryReader {
164 buffer: data,
165 position: 0,
166 original_offset,
167 #[cfg(feature = "features")]
168 features: WasmFeatures::all(),
169 }
170 }
171
172 /// Creates a new binary reader which will parse the `data` provided.
173 ///
174 /// The `original_offset` provided is used for byte offsets in errors that
175 /// are generated. That offset is added to the current position in `data`.
176 /// This can be helpful when `data` is just a window of a view into a larger
177 /// wasm binary perhaps not even entirely stored locally.
178 ///
179 /// The `features` argument provided controls which WebAssembly features are
180 /// active when parsing this data. Wasm features typically don't affect
181 /// parsing too too much and are generally more applicable during
182 /// validation, but features and proposals will often reinterpret
183 /// previously-invalid constructs as now-valid things meaning something
184 /// slightly different. This means that invalid bytes before a feature may
185 /// now be interpreted differently after a feature is implemented. This
186 /// means that the set of activated features can affect what errors are
187 /// generated and when they are generated.
188 ///
189 /// In general it's safe to pass `WasmFeatures::all()` here. There's no
190 /// downside to enabling all features while parsing and only enabling a
191 /// subset of features during validation.
192 ///
193 /// Note that the activated set of features does not guarantee that
194 /// `BinaryReader` will return an error for disabled features. For example
195 /// if SIMD is disabled then SIMD instructions will still be parsed via
196 /// [`BinaryReader::visit_operator`]. Validation must still be performed to
197 /// provide a strict guarantee that if a feature is disabled that a binary
198 /// doesn't leverage the feature. The activated set of features here instead
199 /// only affects locations where preexisting bytes are reinterpreted in
200 /// different ways with future proposals, such as the `memarg` moving from a
201 /// 32-bit offset to a 64-bit offset with the `memory64` proposal.
202 #[cfg(feature = "features")]
203 pub fn new_features(
204 data: &[u8],
205 original_offset: usize,
206 features: WasmFeatures,
207 ) -> BinaryReader {
208 BinaryReader {
209 buffer: data,
210 position: 0,
211 original_offset,
212 features,
213 }
214 }
215
216 /// "Shrinks" this binary reader to retain only the buffer left-to-parse.
217 ///
218 /// The primary purpose of this method is to change the return value of the
219 /// `range()` method. That method returns the range of the original buffer
220 /// within the wasm binary so calling `range()` on the returned
221 /// `BinaryReader` will return a smaller range than if `range()` is called
222 /// on `self`.
223 ///
224 /// Otherwise parsing values from either `self` or the return value should
225 /// return the same thing.
226 pub(crate) fn shrink(&self) -> BinaryReader<'a> {
227 BinaryReader {
228 buffer: &self.buffer[self.position..],
229 position: 0,
230 original_offset: self.original_offset + self.position,
231 #[cfg(feature = "features")]
232 features: self.features,
233 }
234 }
235
236 /// Gets the original position of the binary reader.
237 #[inline]
238 pub fn original_position(&self) -> usize {
239 self.original_offset + self.position
240 }
241
242 /// Returns the currently active set of wasm features that this reader is
243 /// using while parsing.
244 ///
245 /// For more information see [`BinaryReader::new`].
246 #[cfg(feature = "features")]
247 pub fn features(&self) -> WasmFeatures {
248 self.features
249 }
250
251 /// Sets the wasm features active while parsing to the `features` specified.
252 ///
253 /// For more information see [`BinaryReader::new`].
254 #[cfg(feature = "features")]
255 pub fn set_features(&mut self, features: WasmFeatures) {
256 self.features = features;
257 }
258
259 /// Returns a range from the starting offset to the end of the buffer.
260 pub fn range(&self) -> Range<usize> {
261 self.original_offset..self.original_offset + self.buffer.len()
262 }
263
264 pub(crate) fn remaining_buffer(&self) -> &'a [u8] {
265 &self.buffer[self.position..]
266 }
267
268 fn ensure_has_byte(&self) -> Result<()> {
269 if self.position < self.buffer.len() {
270 Ok(())
271 } else {
272 Err(BinaryReaderError::eof(self.original_position(), 1))
273 }
274 }
275
276 pub(crate) fn ensure_has_bytes(&self, len: usize) -> Result<()> {
277 if self.position + len <= self.buffer.len() {
278 Ok(())
279 } else {
280 let hint = self.position + len - self.buffer.len();
281 Err(BinaryReaderError::eof(self.original_position(), hint))
282 }
283 }
284
285 /// Reads a value of type `T` from this binary reader, advancing the
286 /// internal position in this reader forward as data is read.
287 #[inline]
288 pub fn read<T>(&mut self) -> Result<T>
289 where
290 T: FromReader<'a>,
291 {
292 T::from_reader(self)
293 }
294
295 pub(crate) fn read_u7(&mut self) -> Result<u8> {
296 let b = self.read_u8()?;
297 if (b & 0x80) != 0 {
298 return Err(BinaryReaderError::new(
299 "invalid u7",
300 self.original_position() - 1,
301 ));
302 }
303 Ok(b)
304 }
305
306 pub(crate) fn external_kind_from_byte(byte: u8, offset: usize) -> Result<ExternalKind> {
307 match byte {
308 0x00 => Ok(ExternalKind::Func),
309 0x01 => Ok(ExternalKind::Table),
310 0x02 => Ok(ExternalKind::Memory),
311 0x03 => Ok(ExternalKind::Global),
312 0x04 => Ok(ExternalKind::Tag),
313 x => Err(Self::invalid_leading_byte_error(x, "external kind", offset)),
314 }
315 }
316
317 /// Reads a variable-length 32-bit size from the byte stream while checking
318 /// against a limit.
319 pub fn read_size(&mut self, limit: usize, desc: &str) -> Result<usize> {
320 let pos = self.original_position();
321 let size = self.read_var_u32()? as usize;
322 if size > limit {
323 bail!(pos, "{desc} size is out of bounds");
324 }
325 Ok(size)
326 }
327
328 /// Reads a variable-length 32-bit size from the byte stream while checking
329 /// against a limit.
330 ///
331 /// Then reads that many values of type `T` and returns them as an iterator.
332 ///
333 /// Note that regardless of how many items are read from the returned
334 /// iterator the items will still be parsed from this reader.
335 pub fn read_iter<'me, T>(
336 &'me mut self,
337 limit: usize,
338 desc: &str,
339 ) -> Result<BinaryReaderIter<'a, 'me, T>>
340 where
341 T: FromReader<'a>,
342 {
343 let size = self.read_size(limit, desc)?;
344 Ok(BinaryReaderIter {
345 remaining: size,
346 reader: self,
347 _marker: marker::PhantomData,
348 })
349 }
350
351 fn read_memarg(&mut self, max_align: u8) -> Result<MemArg> {
352 let flags_pos = self.original_position();
353 let mut flags = self.read_var_u32()?;
354
355 let memory = if self.multi_memory() && flags & (1 << 6) != 0 {
356 flags ^= 1 << 6;
357 self.read_var_u32()?
358 } else {
359 0
360 };
361 let align = if flags >= (1 << 6) {
362 return Err(BinaryReaderError::new(
363 "malformed memop alignment: alignment too large",
364 flags_pos,
365 ));
366 } else {
367 flags as u8
368 };
369 let offset = if self.memory64() {
370 self.read_var_u64()?
371 } else {
372 u64::from(self.read_var_u32()?)
373 };
374 Ok(MemArg {
375 align,
376 max_align,
377 offset,
378 memory,
379 })
380 }
381
382 fn read_ordering(&mut self) -> Result<Ordering> {
383 let byte = self.read_var_u32()?;
384 match byte {
385 0 => Ok(Ordering::SeqCst),
386 1 => Ok(Ordering::AcqRel),
387 x => Err(BinaryReaderError::new(
388 &format!("invalid atomic consistency ordering {}", x),
389 self.original_position() - 1,
390 )),
391 }
392 }
393
394 fn read_br_table(&mut self) -> Result<BrTable<'a>> {
395 let cnt = self.read_size(MAX_WASM_BR_TABLE_SIZE, "br_table")?;
396 let reader = self.skip(|reader| {
397 for _ in 0..cnt {
398 reader.read_var_u32()?;
399 }
400 Ok(())
401 })?;
402 let default = self.read_var_u32()?;
403 Ok(BrTable {
404 reader,
405 cnt: cnt as u32,
406 default,
407 })
408 }
409
410 /// Returns whether the `BinaryReader` has reached the end of the file.
411 #[inline]
412 pub fn eof(&self) -> bool {
413 self.position >= self.buffer.len()
414 }
415
416 /// Returns the `BinaryReader`'s current position.
417 #[inline]
418 pub fn current_position(&self) -> usize {
419 self.position
420 }
421
422 /// Returns the number of bytes remaining in the `BinaryReader`.
423 #[inline]
424 pub fn bytes_remaining(&self) -> usize {
425 self.buffer.len() - self.position
426 }
427
428 /// Advances the `BinaryReader` `size` bytes, and returns a slice from the
429 /// current position of `size` length.
430 ///
431 /// # Errors
432 /// If `size` exceeds the remaining length in `BinaryReader`.
433 pub fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> {
434 self.ensure_has_bytes(size)?;
435 let start = self.position;
436 self.position += size;
437 Ok(&self.buffer[start..self.position])
438 }
439
440 /// Reads a length-prefixed list of bytes from this reader and returns a
441 /// new `BinaryReader` to read that list of bytes.
442 pub fn read_reader(&mut self) -> Result<BinaryReader<'a>> {
443 let size = self.read_var_u32()? as usize;
444 self.skip(|reader| {
445 reader.read_bytes(size)?;
446 Ok(())
447 })
448 }
449
450 /// Advances the `BinaryReader` four bytes and returns a `u32`.
451 /// # Errors
452 /// If `BinaryReader` has less than four bytes remaining.
453 pub fn read_u32(&mut self) -> Result<u32> {
454 self.ensure_has_bytes(4)?;
455 let word = u32::from_le_bytes(
456 self.buffer[self.position..self.position + 4]
457 .try_into()
458 .unwrap(),
459 );
460 self.position += 4;
461 Ok(word)
462 }
463
464 /// Advances the `BinaryReader` eight bytes and returns a `u64`.
465 /// # Errors
466 /// If `BinaryReader` has less than eight bytes remaining.
467 pub fn read_u64(&mut self) -> Result<u64> {
468 self.ensure_has_bytes(8)?;
469 let word = u64::from_le_bytes(
470 self.buffer[self.position..self.position + 8]
471 .try_into()
472 .unwrap(),
473 );
474 self.position += 8;
475 Ok(word)
476 }
477
478 /// Advances the `BinaryReader` a single byte.
479 ///
480 /// # Errors
481 ///
482 /// If `BinaryReader` has no bytes remaining.
483 #[inline]
484 pub fn read_u8(&mut self) -> Result<u8> {
485 let b = match self.buffer.get(self.position) {
486 Some(b) => *b,
487 None => return Err(self.eof_err()),
488 };
489 self.position += 1;
490 Ok(b)
491 }
492
493 #[cold]
494 fn eof_err(&self) -> BinaryReaderError {
495 BinaryReaderError::eof(self.original_position(), 1)
496 }
497
498 /// Advances the `BinaryReader` up to four bytes to parse a variable
499 /// length integer as a `u32`.
500 ///
501 /// # Errors
502 ///
503 /// If `BinaryReader` has less than one or up to four bytes remaining, or
504 /// the integer is larger than 32 bits.
505 #[inline]
506 pub fn read_var_u32(&mut self) -> Result<u32> {
507 // Optimization for single byte i32.
508 let byte = self.read_u8()?;
509 if (byte & 0x80) == 0 {
510 Ok(u32::from(byte))
511 } else {
512 self.read_var_u32_big(byte)
513 }
514 }
515
516 fn read_var_u32_big(&mut self, byte: u8) -> Result<u32> {
517 let mut result = (byte & 0x7F) as u32;
518 let mut shift = 7;
519 loop {
520 let byte = self.read_u8()?;
521 result |= ((byte & 0x7F) as u32) << shift;
522 if shift >= 25 && (byte >> (32 - shift)) != 0 {
523 let msg = if byte & 0x80 != 0 {
524 "invalid var_u32: integer representation too long"
525 } else {
526 "invalid var_u32: integer too large"
527 };
528 // The continuation bit or unused bits are set.
529 return Err(BinaryReaderError::new(msg, self.original_position() - 1));
530 }
531 shift += 7;
532 if (byte & 0x80) == 0 {
533 break;
534 }
535 }
536 Ok(result)
537 }
538
539 /// Advances the `BinaryReader` up to four bytes to parse a variable
540 /// length integer as a `u64`.
541 ///
542 /// # Errors
543 ///
544 /// If `BinaryReader` has less than one or up to eight bytes remaining, or
545 /// the integer is larger than 64 bits.
546 #[inline]
547 pub fn read_var_u64(&mut self) -> Result<u64> {
548 // Optimization for single byte u64.
549 let byte = u64::from(self.read_u8()?);
550 if (byte & 0x80) == 0 {
551 Ok(byte)
552 } else {
553 self.read_var_u64_big(byte)
554 }
555 }
556
557 fn read_var_u64_big(&mut self, byte: u64) -> Result<u64> {
558 let mut result = byte & 0x7F;
559 let mut shift = 7;
560 loop {
561 let byte = u64::from(self.read_u8()?);
562 result |= (byte & 0x7F) << shift;
563 if shift >= 57 && (byte >> (64 - shift)) != 0 {
564 let msg = if byte & 0x80 != 0 {
565 "invalid var_u64: integer representation too long"
566 } else {
567 "invalid var_u64: integer too large"
568 };
569 // The continuation bit or unused bits are set.
570 return Err(BinaryReaderError::new(msg, self.original_position() - 1));
571 }
572 shift += 7;
573 if (byte & 0x80) == 0 {
574 break;
575 }
576 }
577 Ok(result)
578 }
579
580 /// Executes `f` to skip some data in this binary reader and then returns a
581 /// reader which will read the skipped data.
582 pub fn skip(&mut self, f: impl FnOnce(&mut Self) -> Result<()>) -> Result<Self> {
583 let start = self.position;
584 f(self)?;
585 let mut ret = self.clone();
586 ret.buffer = &self.buffer[start..self.position];
587 ret.position = 0;
588 ret.original_offset = self.original_offset + start;
589 Ok(ret)
590 }
591
592 /// Advances the `BinaryReader` past a WebAssembly string. This method does
593 /// not perform any utf-8 validation.
594 /// # Errors
595 /// If `BinaryReader` has less than four bytes, the string's length exceeds
596 /// the remaining bytes, or the string length
597 /// exceeds `limits::MAX_WASM_STRING_SIZE`.
598 pub fn skip_string(&mut self) -> Result<()> {
599 let len = self.read_var_u32()? as usize;
600 if len > MAX_WASM_STRING_SIZE {
601 return Err(BinaryReaderError::new(
602 "string size out of bounds",
603 self.original_position() - 1,
604 ));
605 }
606 self.ensure_has_bytes(len)?;
607 self.position += len;
608 Ok(())
609 }
610
611 /// Advances the `BinaryReader` up to four bytes to parse a variable
612 /// length integer as a `i32`.
613 /// # Errors
614 /// If `BinaryReader` has less than one or up to four bytes remaining, or
615 /// the integer is larger than 32 bits.
616 #[inline]
617 pub fn read_var_i32(&mut self) -> Result<i32> {
618 // Optimization for single byte i32.
619 let byte = self.read_u8()?;
620 if (byte & 0x80) == 0 {
621 Ok(((byte as i32) << 25) >> 25)
622 } else {
623 self.read_var_i32_big(byte)
624 }
625 }
626
627 fn read_var_i32_big(&mut self, byte: u8) -> Result<i32> {
628 let mut result = (byte & 0x7F) as i32;
629 let mut shift = 7;
630 loop {
631 let byte = self.read_u8()?;
632 result |= ((byte & 0x7F) as i32) << shift;
633 if shift >= 25 {
634 let continuation_bit = (byte & 0x80) != 0;
635 let sign_and_unused_bit = (byte << 1) as i8 >> (32 - shift);
636 if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
637 let msg = if continuation_bit {
638 "invalid var_i32: integer representation too long"
639 } else {
640 "invalid var_i32: integer too large"
641 };
642 return Err(BinaryReaderError::new(msg, self.original_position() - 1));
643 }
644 return Ok(result);
645 }
646 shift += 7;
647 if (byte & 0x80) == 0 {
648 break;
649 }
650 }
651 let ashift = 32 - shift;
652 Ok((result << ashift) >> ashift)
653 }
654
655 /// Advances the `BinaryReader` up to four bytes to parse a variable
656 /// length integer as a signed 33 bit integer, returned as a `i64`.
657 /// # Errors
658 /// If `BinaryReader` has less than one or up to five bytes remaining, or
659 /// the integer is larger than 33 bits.
660 pub fn read_var_s33(&mut self) -> Result<i64> {
661 // Optimization for single byte.
662 let byte = self.read_u8()?;
663 if (byte & 0x80) == 0 {
664 return Ok(((byte as i8) << 1) as i64 >> 1);
665 }
666
667 let mut result = (byte & 0x7F) as i64;
668 let mut shift = 7;
669 loop {
670 let byte = self.read_u8()?;
671 result |= ((byte & 0x7F) as i64) << shift;
672 if shift >= 25 {
673 let continuation_bit = (byte & 0x80) != 0;
674 let sign_and_unused_bit = (byte << 1) as i8 >> (33 - shift);
675 if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
676 return Err(BinaryReaderError::new(
677 "invalid var_s33: integer representation too long",
678 self.original_position() - 1,
679 ));
680 }
681 return Ok(result);
682 }
683 shift += 7;
684 if (byte & 0x80) == 0 {
685 break;
686 }
687 }
688 let ashift = 64 - shift;
689 Ok((result << ashift) >> ashift)
690 }
691
692 /// Advances the `BinaryReader` up to eight bytes to parse a variable
693 /// length integer as a 64 bit integer, returned as a `i64`.
694 /// # Errors
695 /// If `BinaryReader` has less than one or up to eight bytes remaining, or
696 /// the integer is larger than 64 bits.
697 pub fn read_var_i64(&mut self) -> Result<i64> {
698 let mut result: i64 = 0;
699 let mut shift = 0;
700 loop {
701 let byte = self.read_u8()?;
702 result |= i64::from(byte & 0x7F) << shift;
703 if shift >= 57 {
704 let continuation_bit = (byte & 0x80) != 0;
705 let sign_and_unused_bit = ((byte << 1) as i8) >> (64 - shift);
706 if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
707 let msg = if continuation_bit {
708 "invalid var_i64: integer representation too long"
709 } else {
710 "invalid var_i64: integer too large"
711 };
712 return Err(BinaryReaderError::new(msg, self.original_position() - 1));
713 }
714 return Ok(result);
715 }
716 shift += 7;
717 if (byte & 0x80) == 0 {
718 break;
719 }
720 }
721 let ashift = 64 - shift;
722 Ok((result << ashift) >> ashift)
723 }
724
725 /// Advances the `BinaryReader` four bytes to parse a 32 bit floating point
726 /// number, returned as `Ieee32`.
727 /// # Errors
728 /// If `BinaryReader` has less than four bytes remaining.
729 pub fn read_f32(&mut self) -> Result<Ieee32> {
730 let value = self.read_u32()?;
731 Ok(Ieee32(value))
732 }
733
734 /// Advances the `BinaryReader` eight bytes to parse a 64 bit floating point
735 /// number, returned as `Ieee64`.
736 /// # Errors
737 /// If `BinaryReader` has less than eight bytes remaining.
738 pub fn read_f64(&mut self) -> Result<Ieee64> {
739 let value = self.read_u64()?;
740 Ok(Ieee64(value))
741 }
742
743 /// (internal) Reads a fixed-size WebAssembly string from the module.
744 fn internal_read_string(&mut self, len: usize) -> Result<&'a str> {
745 let bytes = self.read_bytes(len)?;
746 str::from_utf8(bytes).map_err(|_| {
747 BinaryReaderError::new("malformed UTF-8 encoding", self.original_position() - 1)
748 })
749 }
750
751 /// Reads a WebAssembly string from the module.
752 ///
753 /// # Errors
754 ///
755 /// If `BinaryReader` has less than up to four bytes remaining, the string's
756 /// length exceeds the remaining bytes, the string's length exceeds
757 /// `limits::MAX_WASM_STRING_SIZE`, or the string contains invalid utf-8.
758 pub fn read_string(&mut self) -> Result<&'a str> {
759 let len = self.read_var_u32()? as usize;
760 if len > MAX_WASM_STRING_SIZE {
761 return Err(BinaryReaderError::new(
762 "string size out of bounds",
763 self.original_position() - 1,
764 ));
765 }
766 return self.internal_read_string(len);
767 }
768
769 /// Reads a unlimited WebAssembly string from the module.
770 ///
771 /// Note that this is similar to [`BinaryReader::read_string`] except that
772 /// it will not limit the size of the returned string by
773 /// `limits::MAX_WASM_STRING_SIZE`.
774 pub fn read_unlimited_string(&mut self) -> Result<&'a str> {
775 let len = self.read_var_u32()? as usize;
776 return self.internal_read_string(len);
777 }
778
779 #[cold]
780 pub(crate) fn invalid_leading_byte<T>(&self, byte: u8, desc: &str) -> Result<T> {
781 Err(Self::invalid_leading_byte_error(
782 byte,
783 desc,
784 self.original_position() - 1,
785 ))
786 }
787
788 pub(crate) fn invalid_leading_byte_error(
789 byte: u8,
790 desc: &str,
791 offset: usize,
792 ) -> BinaryReaderError {
793 format_err!(offset, "invalid leading byte (0x{byte:x}) for {desc}")
794 }
795
796 pub(crate) fn peek(&self) -> Result<u8> {
797 self.ensure_has_byte()?;
798 Ok(self.buffer[self.position])
799 }
800
801 pub(crate) fn read_block_type(&mut self) -> Result<BlockType> {
802 let b = self.peek()?;
803
804 // Block types are encoded as either 0x40, a `valtype`, or `s33`. All
805 // current `valtype` encodings are negative numbers when encoded with
806 // sleb128, but it's also required that valtype encodings are in their
807 // canonical form. For example an overlong encoding of -1 as `0xff 0x7f`
808 // is not valid and it is required to be `0x7f`. This means that we
809 // can't simply match on the `s33` that pops out below since reading the
810 // whole `s33` might read an overlong encoding.
811 //
812 // To test for this the first byte `b` is inspected. The highest bit,
813 // the continuation bit in LEB128 encoding, must be clear. The next bit,
814 // the sign bit, must be set to indicate that the number is negative. If
815 // these two conditions hold then we're guaranteed that this is a
816 // negative number.
817 //
818 // After this a value type is read directly instead of looking for an
819 // indexed value type.
820 if b & 0x80 == 0 && b & 0x40 != 0 {
821 if b == 0x40 {
822 self.position += 1;
823 return Ok(BlockType::Empty);
824 }
825 return Ok(BlockType::Type(self.read()?));
826 }
827
828 // Not empty or a singular type, so read the function type index
829 let idx = self.read_var_s33()?;
830 match u32::try_from(idx) {
831 Ok(idx) => Ok(BlockType::FuncType(idx)),
832 Err(_) => {
833 return Err(BinaryReaderError::new(
834 "invalid function type",
835 self.original_position(),
836 ));
837 }
838 }
839 }
840
841 /// Visit the next available operator with the specified [`VisitOperator`] instance.
842 ///
843 /// Note that this does not implicitly propagate any additional information such as instruction
844 /// offsets. In order to do so, consider storing such data within the visitor before visiting.
845 ///
846 /// # Errors
847 ///
848 /// If `BinaryReader` has less bytes remaining than required to parse the `Operator`.
849 ///
850 /// # Examples
851 ///
852 /// Store an offset for use in diagnostics or any other purposes:
853 ///
854 /// ```
855 /// # use wasmparser::{BinaryReader, VisitOperator, Result, for_each_visit_operator};
856 ///
857 /// pub fn dump(mut reader: BinaryReader) -> Result<()> {
858 /// let mut visitor = Dumper { offset: 0 };
859 /// while !reader.eof() {
860 /// visitor.offset = reader.original_position();
861 /// reader.visit_operator(&mut visitor)?;
862 /// }
863 /// Ok(())
864 /// }
865 ///
866 /// struct Dumper {
867 /// offset: usize
868 /// }
869 ///
870 /// macro_rules! define_visit_operator {
871 /// ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
872 /// $(
873 /// fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
874 /// println!("{}: {}", self.offset, stringify!($visit));
875 /// }
876 /// )*
877 /// }
878 /// }
879 ///
880 /// impl<'a> VisitOperator<'a> for Dumper {
881 /// type Output = ();
882 /// for_each_visit_operator!(define_visit_operator);
883 /// }
884 ///
885 /// ```
886 pub fn visit_operator<T>(&mut self, visitor: &mut T) -> Result<<T as VisitOperator<'a>>::Output>
887 where
888 T: VisitOperator<'a>,
889 {
890 let pos = self.original_position();
891 let code = self.read_u8()? as u8;
892 Ok(match code {
893 0x00 => visitor.visit_unreachable(),
894 0x01 => visitor.visit_nop(),
895 0x02 => visitor.visit_block(self.read_block_type()?),
896 0x03 => visitor.visit_loop(self.read_block_type()?),
897 0x04 => visitor.visit_if(self.read_block_type()?),
898 0x05 => visitor.visit_else(),
899 0x06 => visitor.visit_try(self.read_block_type()?),
900 0x07 => visitor.visit_catch(self.read_var_u32()?),
901 0x08 => visitor.visit_throw(self.read_var_u32()?),
902 0x09 => visitor.visit_rethrow(self.read_var_u32()?),
903 0x0a => visitor.visit_throw_ref(),
904 0x0b => visitor.visit_end(),
905 0x0c => visitor.visit_br(self.read_var_u32()?),
906 0x0d => visitor.visit_br_if(self.read_var_u32()?),
907 0x0e => visitor.visit_br_table(self.read_br_table()?),
908 0x0f => visitor.visit_return(),
909 0x10 => visitor.visit_call(self.read_var_u32()?),
910 0x11 => {
911 let index = self.read_var_u32()?;
912 let table = self.read_table_index_or_zero_if_not_reference_types()?;
913 visitor.visit_call_indirect(index, table)
914 }
915 0x12 => visitor.visit_return_call(self.read_var_u32()?),
916 0x13 => visitor.visit_return_call_indirect(self.read_var_u32()?, self.read_var_u32()?),
917 0x14 => visitor.visit_call_ref(self.read()?),
918 0x15 => visitor.visit_return_call_ref(self.read()?),
919 0x18 => visitor.visit_delegate(self.read_var_u32()?),
920 0x19 => visitor.visit_catch_all(),
921 0x1a => visitor.visit_drop(),
922 0x1b => visitor.visit_select(),
923 0x1c => {
924 let results = self.read_var_u32()?;
925 if results != 1 {
926 return Err(BinaryReaderError::new(
927 "invalid result arity",
928 self.position,
929 ));
930 }
931 visitor.visit_typed_select(self.read()?)
932 }
933 0x1f => visitor.visit_try_table(self.read()?),
934
935 0x20 => visitor.visit_local_get(self.read_var_u32()?),
936 0x21 => visitor.visit_local_set(self.read_var_u32()?),
937 0x22 => visitor.visit_local_tee(self.read_var_u32()?),
938 0x23 => visitor.visit_global_get(self.read_var_u32()?),
939 0x24 => visitor.visit_global_set(self.read_var_u32()?),
940 0x25 => visitor.visit_table_get(self.read_var_u32()?),
941 0x26 => visitor.visit_table_set(self.read_var_u32()?),
942
943 0x28 => visitor.visit_i32_load(self.read_memarg(2)?),
944 0x29 => visitor.visit_i64_load(self.read_memarg(3)?),
945 0x2a => visitor.visit_f32_load(self.read_memarg(2)?),
946 0x2b => visitor.visit_f64_load(self.read_memarg(3)?),
947 0x2c => visitor.visit_i32_load8_s(self.read_memarg(0)?),
948 0x2d => visitor.visit_i32_load8_u(self.read_memarg(0)?),
949 0x2e => visitor.visit_i32_load16_s(self.read_memarg(1)?),
950 0x2f => visitor.visit_i32_load16_u(self.read_memarg(1)?),
951 0x30 => visitor.visit_i64_load8_s(self.read_memarg(0)?),
952 0x31 => visitor.visit_i64_load8_u(self.read_memarg(0)?),
953 0x32 => visitor.visit_i64_load16_s(self.read_memarg(1)?),
954 0x33 => visitor.visit_i64_load16_u(self.read_memarg(1)?),
955 0x34 => visitor.visit_i64_load32_s(self.read_memarg(2)?),
956 0x35 => visitor.visit_i64_load32_u(self.read_memarg(2)?),
957 0x36 => visitor.visit_i32_store(self.read_memarg(2)?),
958 0x37 => visitor.visit_i64_store(self.read_memarg(3)?),
959 0x38 => visitor.visit_f32_store(self.read_memarg(2)?),
960 0x39 => visitor.visit_f64_store(self.read_memarg(3)?),
961 0x3a => visitor.visit_i32_store8(self.read_memarg(0)?),
962 0x3b => visitor.visit_i32_store16(self.read_memarg(1)?),
963 0x3c => visitor.visit_i64_store8(self.read_memarg(0)?),
964 0x3d => visitor.visit_i64_store16(self.read_memarg(1)?),
965 0x3e => visitor.visit_i64_store32(self.read_memarg(2)?),
966 0x3f => {
967 let mem = self.read_memory_index_or_zero_if_not_multi_memory()?;
968 visitor.visit_memory_size(mem)
969 }
970 0x40 => {
971 let mem = self.read_memory_index_or_zero_if_not_multi_memory()?;
972 visitor.visit_memory_grow(mem)
973 }
974
975 0x41 => visitor.visit_i32_const(self.read_var_i32()?),
976 0x42 => visitor.visit_i64_const(self.read_var_i64()?),
977 0x43 => visitor.visit_f32_const(self.read_f32()?),
978 0x44 => visitor.visit_f64_const(self.read_f64()?),
979
980 0x45 => visitor.visit_i32_eqz(),
981 0x46 => visitor.visit_i32_eq(),
982 0x47 => visitor.visit_i32_ne(),
983 0x48 => visitor.visit_i32_lt_s(),
984 0x49 => visitor.visit_i32_lt_u(),
985 0x4a => visitor.visit_i32_gt_s(),
986 0x4b => visitor.visit_i32_gt_u(),
987 0x4c => visitor.visit_i32_le_s(),
988 0x4d => visitor.visit_i32_le_u(),
989 0x4e => visitor.visit_i32_ge_s(),
990 0x4f => visitor.visit_i32_ge_u(),
991 0x50 => visitor.visit_i64_eqz(),
992 0x51 => visitor.visit_i64_eq(),
993 0x52 => visitor.visit_i64_ne(),
994 0x53 => visitor.visit_i64_lt_s(),
995 0x54 => visitor.visit_i64_lt_u(),
996 0x55 => visitor.visit_i64_gt_s(),
997 0x56 => visitor.visit_i64_gt_u(),
998 0x57 => visitor.visit_i64_le_s(),
999 0x58 => visitor.visit_i64_le_u(),
1000 0x59 => visitor.visit_i64_ge_s(),
1001 0x5a => visitor.visit_i64_ge_u(),
1002 0x5b => visitor.visit_f32_eq(),
1003 0x5c => visitor.visit_f32_ne(),
1004 0x5d => visitor.visit_f32_lt(),
1005 0x5e => visitor.visit_f32_gt(),
1006 0x5f => visitor.visit_f32_le(),
1007 0x60 => visitor.visit_f32_ge(),
1008 0x61 => visitor.visit_f64_eq(),
1009 0x62 => visitor.visit_f64_ne(),
1010 0x63 => visitor.visit_f64_lt(),
1011 0x64 => visitor.visit_f64_gt(),
1012 0x65 => visitor.visit_f64_le(),
1013 0x66 => visitor.visit_f64_ge(),
1014 0x67 => visitor.visit_i32_clz(),
1015 0x68 => visitor.visit_i32_ctz(),
1016 0x69 => visitor.visit_i32_popcnt(),
1017 0x6a => visitor.visit_i32_add(),
1018 0x6b => visitor.visit_i32_sub(),
1019 0x6c => visitor.visit_i32_mul(),
1020 0x6d => visitor.visit_i32_div_s(),
1021 0x6e => visitor.visit_i32_div_u(),
1022 0x6f => visitor.visit_i32_rem_s(),
1023 0x70 => visitor.visit_i32_rem_u(),
1024 0x71 => visitor.visit_i32_and(),
1025 0x72 => visitor.visit_i32_or(),
1026 0x73 => visitor.visit_i32_xor(),
1027 0x74 => visitor.visit_i32_shl(),
1028 0x75 => visitor.visit_i32_shr_s(),
1029 0x76 => visitor.visit_i32_shr_u(),
1030 0x77 => visitor.visit_i32_rotl(),
1031 0x78 => visitor.visit_i32_rotr(),
1032 0x79 => visitor.visit_i64_clz(),
1033 0x7a => visitor.visit_i64_ctz(),
1034 0x7b => visitor.visit_i64_popcnt(),
1035 0x7c => visitor.visit_i64_add(),
1036 0x7d => visitor.visit_i64_sub(),
1037 0x7e => visitor.visit_i64_mul(),
1038 0x7f => visitor.visit_i64_div_s(),
1039 0x80 => visitor.visit_i64_div_u(),
1040 0x81 => visitor.visit_i64_rem_s(),
1041 0x82 => visitor.visit_i64_rem_u(),
1042 0x83 => visitor.visit_i64_and(),
1043 0x84 => visitor.visit_i64_or(),
1044 0x85 => visitor.visit_i64_xor(),
1045 0x86 => visitor.visit_i64_shl(),
1046 0x87 => visitor.visit_i64_shr_s(),
1047 0x88 => visitor.visit_i64_shr_u(),
1048 0x89 => visitor.visit_i64_rotl(),
1049 0x8a => visitor.visit_i64_rotr(),
1050 0x8b => visitor.visit_f32_abs(),
1051 0x8c => visitor.visit_f32_neg(),
1052 0x8d => visitor.visit_f32_ceil(),
1053 0x8e => visitor.visit_f32_floor(),
1054 0x8f => visitor.visit_f32_trunc(),
1055 0x90 => visitor.visit_f32_nearest(),
1056 0x91 => visitor.visit_f32_sqrt(),
1057 0x92 => visitor.visit_f32_add(),
1058 0x93 => visitor.visit_f32_sub(),
1059 0x94 => visitor.visit_f32_mul(),
1060 0x95 => visitor.visit_f32_div(),
1061 0x96 => visitor.visit_f32_min(),
1062 0x97 => visitor.visit_f32_max(),
1063 0x98 => visitor.visit_f32_copysign(),
1064 0x99 => visitor.visit_f64_abs(),
1065 0x9a => visitor.visit_f64_neg(),
1066 0x9b => visitor.visit_f64_ceil(),
1067 0x9c => visitor.visit_f64_floor(),
1068 0x9d => visitor.visit_f64_trunc(),
1069 0x9e => visitor.visit_f64_nearest(),
1070 0x9f => visitor.visit_f64_sqrt(),
1071 0xa0 => visitor.visit_f64_add(),
1072 0xa1 => visitor.visit_f64_sub(),
1073 0xa2 => visitor.visit_f64_mul(),
1074 0xa3 => visitor.visit_f64_div(),
1075 0xa4 => visitor.visit_f64_min(),
1076 0xa5 => visitor.visit_f64_max(),
1077 0xa6 => visitor.visit_f64_copysign(),
1078 0xa7 => visitor.visit_i32_wrap_i64(),
1079 0xa8 => visitor.visit_i32_trunc_f32_s(),
1080 0xa9 => visitor.visit_i32_trunc_f32_u(),
1081 0xaa => visitor.visit_i32_trunc_f64_s(),
1082 0xab => visitor.visit_i32_trunc_f64_u(),
1083 0xac => visitor.visit_i64_extend_i32_s(),
1084 0xad => visitor.visit_i64_extend_i32_u(),
1085 0xae => visitor.visit_i64_trunc_f32_s(),
1086 0xaf => visitor.visit_i64_trunc_f32_u(),
1087 0xb0 => visitor.visit_i64_trunc_f64_s(),
1088 0xb1 => visitor.visit_i64_trunc_f64_u(),
1089 0xb2 => visitor.visit_f32_convert_i32_s(),
1090 0xb3 => visitor.visit_f32_convert_i32_u(),
1091 0xb4 => visitor.visit_f32_convert_i64_s(),
1092 0xb5 => visitor.visit_f32_convert_i64_u(),
1093 0xb6 => visitor.visit_f32_demote_f64(),
1094 0xb7 => visitor.visit_f64_convert_i32_s(),
1095 0xb8 => visitor.visit_f64_convert_i32_u(),
1096 0xb9 => visitor.visit_f64_convert_i64_s(),
1097 0xba => visitor.visit_f64_convert_i64_u(),
1098 0xbb => visitor.visit_f64_promote_f32(),
1099 0xbc => visitor.visit_i32_reinterpret_f32(),
1100 0xbd => visitor.visit_i64_reinterpret_f64(),
1101 0xbe => visitor.visit_f32_reinterpret_i32(),
1102 0xbf => visitor.visit_f64_reinterpret_i64(),
1103
1104 0xc0 => visitor.visit_i32_extend8_s(),
1105 0xc1 => visitor.visit_i32_extend16_s(),
1106 0xc2 => visitor.visit_i64_extend8_s(),
1107 0xc3 => visitor.visit_i64_extend16_s(),
1108 0xc4 => visitor.visit_i64_extend32_s(),
1109
1110 0xd0 => visitor.visit_ref_null(self.read()?),
1111 0xd1 => visitor.visit_ref_is_null(),
1112 0xd2 => visitor.visit_ref_func(self.read_var_u32()?),
1113 0xd3 => visitor.visit_ref_eq(),
1114 0xd4 => visitor.visit_ref_as_non_null(),
1115 0xd5 => visitor.visit_br_on_null(self.read_var_u32()?),
1116 0xd6 => visitor.visit_br_on_non_null(self.read_var_u32()?),
1117
1118 0xe0 => visitor.visit_cont_new(self.read_var_u32()?),
1119 0xe1 => visitor.visit_cont_bind(self.read_var_u32()?, self.read_var_u32()?),
1120 0xe2 => visitor.visit_suspend(self.read_var_u32()?),
1121 0xe3 => visitor.visit_resume(self.read_var_u32()?, self.read()?),
1122 0xe4 => {
1123 visitor.visit_resume_throw(self.read_var_u32()?, self.read_var_u32()?, self.read()?)
1124 }
1125 0xe5 => visitor.visit_switch(self.read_var_u32()?, self.read_var_u32()?),
1126
1127 0xfb => self.visit_0xfb_operator(pos, visitor)?,
1128 0xfc => self.visit_0xfc_operator(pos, visitor)?,
1129 0xfd => {
1130 #[cfg(feature = "simd")]
1131 if let Some(mut visitor) = visitor.simd_visitor() {
1132 return self.visit_0xfd_operator(pos, &mut visitor);
1133 }
1134 bail!(pos, "unexpected SIMD opcode: 0x{code:x}")
1135 }
1136 0xfe => self.visit_0xfe_operator(pos, visitor)?,
1137
1138 _ => bail!(pos, "illegal opcode: 0x{code:x}"),
1139 })
1140 }
1141
1142 fn visit_0xfb_operator<T>(
1143 &mut self,
1144 pos: usize,
1145 visitor: &mut T,
1146 ) -> Result<<T as VisitOperator<'a>>::Output>
1147 where
1148 T: VisitOperator<'a>,
1149 {
1150 let code = self.read_var_u32()?;
1151 Ok(match code {
1152 0x0 => {
1153 let type_index = self.read_var_u32()?;
1154 visitor.visit_struct_new(type_index)
1155 }
1156 0x01 => {
1157 let type_index = self.read_var_u32()?;
1158 visitor.visit_struct_new_default(type_index)
1159 }
1160 0x02 => {
1161 let type_index = self.read_var_u32()?;
1162 let field_index = self.read_var_u32()?;
1163 visitor.visit_struct_get(type_index, field_index)
1164 }
1165 0x03 => {
1166 let type_index = self.read_var_u32()?;
1167 let field_index = self.read_var_u32()?;
1168 visitor.visit_struct_get_s(type_index, field_index)
1169 }
1170 0x04 => {
1171 let type_index = self.read_var_u32()?;
1172 let field_index = self.read_var_u32()?;
1173 visitor.visit_struct_get_u(type_index, field_index)
1174 }
1175 0x05 => {
1176 let type_index = self.read_var_u32()?;
1177 let field_index = self.read_var_u32()?;
1178 visitor.visit_struct_set(type_index, field_index)
1179 }
1180 0x06 => {
1181 let type_index = self.read_var_u32()?;
1182 visitor.visit_array_new(type_index)
1183 }
1184 0x07 => {
1185 let type_index = self.read_var_u32()?;
1186 visitor.visit_array_new_default(type_index)
1187 }
1188 0x08 => {
1189 let type_index = self.read_var_u32()?;
1190 let n = self.read_var_u32()?;
1191 visitor.visit_array_new_fixed(type_index, n)
1192 }
1193 0x09 => {
1194 let type_index = self.read_var_u32()?;
1195 let data_index = self.read_var_u32()?;
1196 visitor.visit_array_new_data(type_index, data_index)
1197 }
1198 0x0a => {
1199 let type_index = self.read_var_u32()?;
1200 let elem_index = self.read_var_u32()?;
1201 visitor.visit_array_new_elem(type_index, elem_index)
1202 }
1203 0x0b => {
1204 let type_index = self.read_var_u32()?;
1205 visitor.visit_array_get(type_index)
1206 }
1207 0x0c => {
1208 let type_index = self.read_var_u32()?;
1209 visitor.visit_array_get_s(type_index)
1210 }
1211 0x0d => {
1212 let type_index = self.read_var_u32()?;
1213 visitor.visit_array_get_u(type_index)
1214 }
1215 0x0e => {
1216 let type_index = self.read_var_u32()?;
1217 visitor.visit_array_set(type_index)
1218 }
1219 0x0f => visitor.visit_array_len(),
1220 0x10 => {
1221 let type_index = self.read_var_u32()?;
1222 visitor.visit_array_fill(type_index)
1223 }
1224 0x11 => {
1225 let type_index_dst = self.read_var_u32()?;
1226 let type_index_src = self.read_var_u32()?;
1227 visitor.visit_array_copy(type_index_dst, type_index_src)
1228 }
1229 0x12 => {
1230 let type_index = self.read_var_u32()?;
1231 let data_index = self.read_var_u32()?;
1232 visitor.visit_array_init_data(type_index, data_index)
1233 }
1234 0x13 => {
1235 let type_index = self.read_var_u32()?;
1236 let elem_index = self.read_var_u32()?;
1237 visitor.visit_array_init_elem(type_index, elem_index)
1238 }
1239 0x14 => visitor.visit_ref_test_non_null(self.read()?),
1240 0x15 => visitor.visit_ref_test_nullable(self.read()?),
1241 0x16 => visitor.visit_ref_cast_non_null(self.read()?),
1242 0x17 => visitor.visit_ref_cast_nullable(self.read()?),
1243 0x18 => {
1244 let pos = self.original_position();
1245 let cast_flags = self.read_u8()?;
1246 let relative_depth = self.read_var_u32()?;
1247 let (from_type_nullable, to_type_nullable) = match cast_flags {
1248 0b00 => (false, false),
1249 0b01 => (true, false),
1250 0b10 => (false, true),
1251 0b11 => (true, true),
1252 _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"),
1253 };
1254 let from_heap_type = self.read()?;
1255 let from_ref_type =
1256 RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| {
1257 format_err!(pos, "implementation error: type index too large")
1258 })?;
1259 let to_heap_type = self.read()?;
1260 let to_ref_type =
1261 RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| {
1262 format_err!(pos, "implementation error: type index too large")
1263 })?;
1264 visitor.visit_br_on_cast(relative_depth, from_ref_type, to_ref_type)
1265 }
1266 0x19 => {
1267 let pos = self.original_position();
1268 let cast_flags = self.read_u8()?;
1269 let relative_depth = self.read_var_u32()?;
1270 let (from_type_nullable, to_type_nullable) = match cast_flags {
1271 0 => (false, false),
1272 1 => (true, false),
1273 2 => (false, true),
1274 3 => (true, true),
1275 _ => bail!(pos, "invalid cast flags: {cast_flags:08b}"),
1276 };
1277 let from_heap_type = self.read()?;
1278 let from_ref_type =
1279 RefType::new(from_type_nullable, from_heap_type).ok_or_else(|| {
1280 format_err!(pos, "implementation error: type index too large")
1281 })?;
1282 let to_heap_type = self.read()?;
1283 let to_ref_type =
1284 RefType::new(to_type_nullable, to_heap_type).ok_or_else(|| {
1285 format_err!(pos, "implementation error: type index too large")
1286 })?;
1287 visitor.visit_br_on_cast_fail(relative_depth, from_ref_type, to_ref_type)
1288 }
1289
1290 0x1a => visitor.visit_any_convert_extern(),
1291 0x1b => visitor.visit_extern_convert_any(),
1292
1293 0x1c => visitor.visit_ref_i31(),
1294 0x1d => visitor.visit_i31_get_s(),
1295 0x1e => visitor.visit_i31_get_u(),
1296
1297 _ => bail!(pos, "unknown 0xfb subopcode: 0x{code:x}"),
1298 })
1299 }
1300
1301 fn visit_0xfc_operator<T>(
1302 &mut self,
1303 pos: usize,
1304 visitor: &mut T,
1305 ) -> Result<<T as VisitOperator<'a>>::Output>
1306 where
1307 T: VisitOperator<'a>,
1308 {
1309 let code = self.read_var_u32()?;
1310 Ok(match code {
1311 0x00 => visitor.visit_i32_trunc_sat_f32_s(),
1312 0x01 => visitor.visit_i32_trunc_sat_f32_u(),
1313 0x02 => visitor.visit_i32_trunc_sat_f64_s(),
1314 0x03 => visitor.visit_i32_trunc_sat_f64_u(),
1315 0x04 => visitor.visit_i64_trunc_sat_f32_s(),
1316 0x05 => visitor.visit_i64_trunc_sat_f32_u(),
1317 0x06 => visitor.visit_i64_trunc_sat_f64_s(),
1318 0x07 => visitor.visit_i64_trunc_sat_f64_u(),
1319
1320 0x08 => {
1321 let segment = self.read_var_u32()?;
1322 let mem = self.read_var_u32()?;
1323 visitor.visit_memory_init(segment, mem)
1324 }
1325 0x09 => {
1326 let segment = self.read_var_u32()?;
1327 visitor.visit_data_drop(segment)
1328 }
1329 0x0a => {
1330 let dst = self.read_var_u32()?;
1331 let src = self.read_var_u32()?;
1332 visitor.visit_memory_copy(dst, src)
1333 }
1334 0x0b => {
1335 let mem = self.read_var_u32()?;
1336 visitor.visit_memory_fill(mem)
1337 }
1338 0x0c => {
1339 let segment = self.read_var_u32()?;
1340 let table = self.read_var_u32()?;
1341 visitor.visit_table_init(segment, table)
1342 }
1343 0x0d => {
1344 let segment = self.read_var_u32()?;
1345 visitor.visit_elem_drop(segment)
1346 }
1347 0x0e => {
1348 let dst_table = self.read_var_u32()?;
1349 let src_table = self.read_var_u32()?;
1350 visitor.visit_table_copy(dst_table, src_table)
1351 }
1352
1353 0x0f => {
1354 let table = self.read_var_u32()?;
1355 visitor.visit_table_grow(table)
1356 }
1357 0x10 => {
1358 let table = self.read_var_u32()?;
1359 visitor.visit_table_size(table)
1360 }
1361
1362 0x11 => {
1363 let table = self.read_var_u32()?;
1364 visitor.visit_table_fill(table)
1365 }
1366
1367 0x12 => {
1368 let mem = self.read_var_u32()?;
1369 visitor.visit_memory_discard(mem)
1370 }
1371
1372 0x13 => visitor.visit_i64_add128(),
1373 0x14 => visitor.visit_i64_sub128(),
1374 0x15 => visitor.visit_i64_mul_wide_s(),
1375 0x16 => visitor.visit_i64_mul_wide_u(),
1376
1377 _ => bail!(pos, "unknown 0xfc subopcode: 0x{code:x}"),
1378 })
1379 }
1380
1381 fn visit_0xfe_operator<T>(
1382 &mut self,
1383 pos: usize,
1384 visitor: &mut T,
1385 ) -> Result<<T as VisitOperator<'a>>::Output>
1386 where
1387 T: VisitOperator<'a>,
1388 {
1389 let code = self.read_var_u32()?;
1390 Ok(match code {
1391 0x00 => visitor.visit_memory_atomic_notify(self.read_memarg(2)?),
1392 0x01 => visitor.visit_memory_atomic_wait32(self.read_memarg(2)?),
1393 0x02 => visitor.visit_memory_atomic_wait64(self.read_memarg(3)?),
1394 0x03 => {
1395 if self.read_u8()? != 0 {
1396 bail!(pos, "nonzero byte after `atomic.fence`");
1397 }
1398 visitor.visit_atomic_fence()
1399 }
1400 0x10 => visitor.visit_i32_atomic_load(self.read_memarg(2)?),
1401 0x11 => visitor.visit_i64_atomic_load(self.read_memarg(3)?),
1402 0x12 => visitor.visit_i32_atomic_load8_u(self.read_memarg(0)?),
1403 0x13 => visitor.visit_i32_atomic_load16_u(self.read_memarg(1)?),
1404 0x14 => visitor.visit_i64_atomic_load8_u(self.read_memarg(0)?),
1405 0x15 => visitor.visit_i64_atomic_load16_u(self.read_memarg(1)?),
1406 0x16 => visitor.visit_i64_atomic_load32_u(self.read_memarg(2)?),
1407 0x17 => visitor.visit_i32_atomic_store(self.read_memarg(2)?),
1408 0x18 => visitor.visit_i64_atomic_store(self.read_memarg(3)?),
1409 0x19 => visitor.visit_i32_atomic_store8(self.read_memarg(0)?),
1410 0x1a => visitor.visit_i32_atomic_store16(self.read_memarg(1)?),
1411 0x1b => visitor.visit_i64_atomic_store8(self.read_memarg(0)?),
1412 0x1c => visitor.visit_i64_atomic_store16(self.read_memarg(1)?),
1413 0x1d => visitor.visit_i64_atomic_store32(self.read_memarg(2)?),
1414 0x1e => visitor.visit_i32_atomic_rmw_add(self.read_memarg(2)?),
1415 0x1f => visitor.visit_i64_atomic_rmw_add(self.read_memarg(3)?),
1416 0x20 => visitor.visit_i32_atomic_rmw8_add_u(self.read_memarg(0)?),
1417 0x21 => visitor.visit_i32_atomic_rmw16_add_u(self.read_memarg(1)?),
1418 0x22 => visitor.visit_i64_atomic_rmw8_add_u(self.read_memarg(0)?),
1419 0x23 => visitor.visit_i64_atomic_rmw16_add_u(self.read_memarg(1)?),
1420 0x24 => visitor.visit_i64_atomic_rmw32_add_u(self.read_memarg(2)?),
1421 0x25 => visitor.visit_i32_atomic_rmw_sub(self.read_memarg(2)?),
1422 0x26 => visitor.visit_i64_atomic_rmw_sub(self.read_memarg(3)?),
1423 0x27 => visitor.visit_i32_atomic_rmw8_sub_u(self.read_memarg(0)?),
1424 0x28 => visitor.visit_i32_atomic_rmw16_sub_u(self.read_memarg(1)?),
1425 0x29 => visitor.visit_i64_atomic_rmw8_sub_u(self.read_memarg(0)?),
1426 0x2a => visitor.visit_i64_atomic_rmw16_sub_u(self.read_memarg(1)?),
1427 0x2b => visitor.visit_i64_atomic_rmw32_sub_u(self.read_memarg(2)?),
1428 0x2c => visitor.visit_i32_atomic_rmw_and(self.read_memarg(2)?),
1429 0x2d => visitor.visit_i64_atomic_rmw_and(self.read_memarg(3)?),
1430 0x2e => visitor.visit_i32_atomic_rmw8_and_u(self.read_memarg(0)?),
1431 0x2f => visitor.visit_i32_atomic_rmw16_and_u(self.read_memarg(1)?),
1432 0x30 => visitor.visit_i64_atomic_rmw8_and_u(self.read_memarg(0)?),
1433 0x31 => visitor.visit_i64_atomic_rmw16_and_u(self.read_memarg(1)?),
1434 0x32 => visitor.visit_i64_atomic_rmw32_and_u(self.read_memarg(2)?),
1435 0x33 => visitor.visit_i32_atomic_rmw_or(self.read_memarg(2)?),
1436 0x34 => visitor.visit_i64_atomic_rmw_or(self.read_memarg(3)?),
1437 0x35 => visitor.visit_i32_atomic_rmw8_or_u(self.read_memarg(0)?),
1438 0x36 => visitor.visit_i32_atomic_rmw16_or_u(self.read_memarg(1)?),
1439 0x37 => visitor.visit_i64_atomic_rmw8_or_u(self.read_memarg(0)?),
1440 0x38 => visitor.visit_i64_atomic_rmw16_or_u(self.read_memarg(1)?),
1441 0x39 => visitor.visit_i64_atomic_rmw32_or_u(self.read_memarg(2)?),
1442 0x3a => visitor.visit_i32_atomic_rmw_xor(self.read_memarg(2)?),
1443 0x3b => visitor.visit_i64_atomic_rmw_xor(self.read_memarg(3)?),
1444 0x3c => visitor.visit_i32_atomic_rmw8_xor_u(self.read_memarg(0)?),
1445 0x3d => visitor.visit_i32_atomic_rmw16_xor_u(self.read_memarg(1)?),
1446 0x3e => visitor.visit_i64_atomic_rmw8_xor_u(self.read_memarg(0)?),
1447 0x3f => visitor.visit_i64_atomic_rmw16_xor_u(self.read_memarg(1)?),
1448 0x40 => visitor.visit_i64_atomic_rmw32_xor_u(self.read_memarg(2)?),
1449 0x41 => visitor.visit_i32_atomic_rmw_xchg(self.read_memarg(2)?),
1450 0x42 => visitor.visit_i64_atomic_rmw_xchg(self.read_memarg(3)?),
1451 0x43 => visitor.visit_i32_atomic_rmw8_xchg_u(self.read_memarg(0)?),
1452 0x44 => visitor.visit_i32_atomic_rmw16_xchg_u(self.read_memarg(1)?),
1453 0x45 => visitor.visit_i64_atomic_rmw8_xchg_u(self.read_memarg(0)?),
1454 0x46 => visitor.visit_i64_atomic_rmw16_xchg_u(self.read_memarg(1)?),
1455 0x47 => visitor.visit_i64_atomic_rmw32_xchg_u(self.read_memarg(2)?),
1456 0x48 => visitor.visit_i32_atomic_rmw_cmpxchg(self.read_memarg(2)?),
1457 0x49 => visitor.visit_i64_atomic_rmw_cmpxchg(self.read_memarg(3)?),
1458 0x4a => visitor.visit_i32_atomic_rmw8_cmpxchg_u(self.read_memarg(0)?),
1459 0x4b => visitor.visit_i32_atomic_rmw16_cmpxchg_u(self.read_memarg(1)?),
1460 0x4c => visitor.visit_i64_atomic_rmw8_cmpxchg_u(self.read_memarg(0)?),
1461 0x4d => visitor.visit_i64_atomic_rmw16_cmpxchg_u(self.read_memarg(1)?),
1462 0x4e => visitor.visit_i64_atomic_rmw32_cmpxchg_u(self.read_memarg(2)?),
1463
1464 // Decode shared-everything-threads proposal.
1465 0x4f => visitor.visit_global_atomic_get(self.read_ordering()?, self.read_var_u32()?),
1466 0x50 => visitor.visit_global_atomic_set(self.read_ordering()?, self.read_var_u32()?),
1467 0x51 => {
1468 visitor.visit_global_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?)
1469 }
1470 0x52 => {
1471 visitor.visit_global_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?)
1472 }
1473 0x53 => {
1474 visitor.visit_global_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?)
1475 }
1476 0x54 => visitor.visit_global_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?),
1477 0x55 => {
1478 visitor.visit_global_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?)
1479 }
1480 0x56 => {
1481 visitor.visit_global_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)
1482 }
1483 0x57 => {
1484 visitor.visit_global_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)
1485 }
1486 0x58 => visitor.visit_table_atomic_get(self.read_ordering()?, self.read_var_u32()?),
1487 0x59 => visitor.visit_table_atomic_set(self.read_ordering()?, self.read_var_u32()?),
1488 0x5a => {
1489 visitor.visit_table_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)
1490 }
1491 0x5b => {
1492 visitor.visit_table_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)
1493 }
1494 0x5c => visitor.visit_struct_atomic_get(
1495 self.read_ordering()?,
1496 self.read_var_u32()?,
1497 self.read_var_u32()?,
1498 ),
1499 0x5d => visitor.visit_struct_atomic_get_s(
1500 self.read_ordering()?,
1501 self.read_var_u32()?,
1502 self.read_var_u32()?,
1503 ),
1504 0x5e => visitor.visit_struct_atomic_get_u(
1505 self.read_ordering()?,
1506 self.read_var_u32()?,
1507 self.read_var_u32()?,
1508 ),
1509 0x5f => visitor.visit_struct_atomic_set(
1510 self.read_ordering()?,
1511 self.read_var_u32()?,
1512 self.read_var_u32()?,
1513 ),
1514 0x60 => visitor.visit_struct_atomic_rmw_add(
1515 self.read_ordering()?,
1516 self.read_var_u32()?,
1517 self.read_var_u32()?,
1518 ),
1519 0x61 => visitor.visit_struct_atomic_rmw_sub(
1520 self.read_ordering()?,
1521 self.read_var_u32()?,
1522 self.read_var_u32()?,
1523 ),
1524 0x62 => visitor.visit_struct_atomic_rmw_and(
1525 self.read_ordering()?,
1526 self.read_var_u32()?,
1527 self.read_var_u32()?,
1528 ),
1529 0x63 => visitor.visit_struct_atomic_rmw_or(
1530 self.read_ordering()?,
1531 self.read_var_u32()?,
1532 self.read_var_u32()?,
1533 ),
1534 0x64 => visitor.visit_struct_atomic_rmw_xor(
1535 self.read_ordering()?,
1536 self.read_var_u32()?,
1537 self.read_var_u32()?,
1538 ),
1539 0x65 => visitor.visit_struct_atomic_rmw_xchg(
1540 self.read_ordering()?,
1541 self.read_var_u32()?,
1542 self.read_var_u32()?,
1543 ),
1544 0x66 => visitor.visit_struct_atomic_rmw_cmpxchg(
1545 self.read_ordering()?,
1546 self.read_var_u32()?,
1547 self.read_var_u32()?,
1548 ),
1549 0x67 => visitor.visit_array_atomic_get(self.read_ordering()?, self.read_var_u32()?),
1550 0x68 => visitor.visit_array_atomic_get_s(self.read_ordering()?, self.read_var_u32()?),
1551 0x69 => visitor.visit_array_atomic_get_u(self.read_ordering()?, self.read_var_u32()?),
1552 0x6a => visitor.visit_array_atomic_set(self.read_ordering()?, self.read_var_u32()?),
1553 0x6b => visitor.visit_array_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?),
1554 0x6c => visitor.visit_array_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?),
1555 0x6d => visitor.visit_array_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?),
1556 0x6e => visitor.visit_array_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?),
1557 0x6f => visitor.visit_array_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?),
1558 0x70 => {
1559 visitor.visit_array_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)
1560 }
1561 0x71 => {
1562 visitor.visit_array_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)
1563 }
1564 0x72 => visitor.visit_ref_i31_shared(),
1565
1566 _ => bail!(pos, "unknown 0xfe subopcode: 0x{code:x}"),
1567 })
1568 }
1569
1570 /// Reads the next available `Operator`.
1571 ///
1572 /// # Errors
1573 ///
1574 /// If `BinaryReader` has less bytes remaining than required to parse
1575 /// the `Operator`.
1576 pub fn read_operator(&mut self) -> Result<Operator<'a>> {
1577 self.visit_operator(&mut OperatorFactory::new())
1578 }
1579
1580 /// Returns whether there is an `end` opcode followed by eof remaining in
1581 /// this reader.
1582 pub fn is_end_then_eof(&self) -> bool {
1583 self.remaining_buffer() == &[0x0b]
1584 }
1585
1586 #[cfg(feature = "simd")]
1587 fn read_lane_index(&mut self, max: u8) -> Result<u8> {
1588 let index = self.read_u8()?;
1589 if index >= max {
1590 return Err(BinaryReaderError::new(
1591 "invalid lane index",
1592 self.original_position() - 1,
1593 ));
1594 }
1595 Ok(index)
1596 }
1597
1598 #[cfg(feature = "simd")]
1599 fn read_v128(&mut self) -> Result<V128> {
1600 let mut bytes = [0; 16];
1601 bytes.clone_from_slice(self.read_bytes(16)?);
1602 Ok(V128(bytes))
1603 }
1604
1605 pub(crate) fn read_header_version(&mut self) -> Result<u32> {
1606 let magic_number = self.read_bytes(4)?;
1607 if magic_number != WASM_MAGIC_NUMBER {
1608 return Err(BinaryReaderError::new(
1609 format!("magic header not detected: bad magic number - expected={WASM_MAGIC_NUMBER:#x?} actual={magic_number:#x?}"),
1610 self.original_position() - 4,
1611 ));
1612 }
1613 self.read_u32()
1614 }
1615
1616 pub(crate) fn skip_const_expr(&mut self) -> Result<()> {
1617 // TODO add skip_operator() method and/or validate ConstExpr operators.
1618 loop {
1619 if let Operator::End = self.read_operator()? {
1620 return Ok(());
1621 }
1622 }
1623 }
1624
1625 fn read_memory_index_or_zero_if_not_multi_memory(&mut self) -> Result<u32> {
1626 if self.multi_memory() {
1627 self.read_var_u32()
1628 } else {
1629 // Before bulk memory this byte was required to be a single zero
1630 // byte, not a LEB-encoded zero, so require a precise zero byte.
1631 match self.read_u8()? {
1632 0 => Ok(0),
1633 _ => bail!(self.original_position() - 1, "zero byte expected"),
1634 }
1635 }
1636 }
1637
1638 fn read_table_index_or_zero_if_not_reference_types(&mut self) -> Result<u32> {
1639 if self.reference_types() {
1640 self.read_var_u32()
1641 } else {
1642 // Before reference types this byte was required to be a single zero
1643 // byte, not a LEB-encoded zero, so require a precise zero byte.
1644 match self.read_u8()? {
1645 0 => Ok(0),
1646 _ => bail!(self.original_position() - 1, "zero byte expected"),
1647 }
1648 }
1649 }
1650}
1651
1652// See documentation on `BinaryReader::features` for more on what's going on
1653// here.
1654macro_rules! define_feature_accessor {
1655 ($feature:ident = $default:expr) => {
1656 impl BinaryReader<'_> {
1657 #[inline]
1658 #[allow(dead_code)]
1659 pub(crate) fn $feature(&self) -> bool {
1660 #[cfg(feature = "features")]
1661 {
1662 self.features.$feature()
1663 }
1664 #[cfg(not(feature = "features"))]
1665 {
1666 true
1667 }
1668 }
1669 }
1670 };
1671}
1672
1673super::features::foreach_wasm_feature!(define_feature_accessor);
1674
1675impl<'a> BrTable<'a> {
1676 /// Returns the number of `br_table` entries, not including the default
1677 /// label
1678 pub fn len(&self) -> u32 {
1679 self.cnt
1680 }
1681
1682 /// Returns whether `BrTable` doesn't have any labels apart from the default one.
1683 pub fn is_empty(&self) -> bool {
1684 self.len() == 0
1685 }
1686
1687 /// Returns the default target of this `br_table` instruction.
1688 pub fn default(&self) -> u32 {
1689 self.default
1690 }
1691
1692 /// Returns the list of targets that this `br_table` instruction will be
1693 /// jumping to.
1694 ///
1695 /// This method will return an iterator which parses each target of this
1696 /// `br_table` except the default target. The returned iterator will
1697 /// yield `self.len()` elements.
1698 ///
1699 /// # Examples
1700 ///
1701 /// ```rust
1702 /// use wasmparser::{BinaryReader, Operator};
1703 ///
1704 /// let buf = [0x0e, 0x02, 0x01, 0x02, 0x00];
1705 /// let mut reader = BinaryReader::new(&buf, 0);
1706 /// let op = reader.read_operator().unwrap();
1707 /// if let Operator::BrTable { targets } = op {
1708 /// let targets = targets.targets().collect::<Result<Vec<_>, _>>().unwrap();
1709 /// assert_eq!(targets, [1, 2]);
1710 /// }
1711 /// ```
1712 pub fn targets(&self) -> BrTableTargets {
1713 BrTableTargets {
1714 reader: self.reader.clone(),
1715 remaining: self.cnt,
1716 }
1717 }
1718}
1719
1720/// An iterator over the targets of a [`BrTable`].
1721///
1722/// # Note
1723///
1724/// This iterator parses each target of the underlying `br_table`
1725/// except for the default target.
1726/// The iterator will yield exactly as many targets as the `br_table` has.
1727pub struct BrTableTargets<'a> {
1728 reader: crate::BinaryReader<'a>,
1729 remaining: u32,
1730}
1731
1732impl<'a> Iterator for BrTableTargets<'a> {
1733 type Item = Result<u32>;
1734
1735 fn size_hint(&self) -> (usize, Option<usize>) {
1736 let remaining: usize = usize::try_from(self.remaining).unwrap_or_else(|error: TryFromIntError| {
1737 panic!("could not convert remaining `u32` into `usize`: {}", error)
1738 });
1739 (remaining, Some(remaining))
1740 }
1741
1742 fn next(&mut self) -> Option<Self::Item> {
1743 if self.remaining == 0 {
1744 if !self.reader.eof() {
1745 return Some(Err(BinaryReaderError::new(
1746 message:"trailing data in br_table",
1747 self.reader.original_position(),
1748 )));
1749 }
1750 return None;
1751 }
1752 self.remaining -= 1;
1753 Some(self.reader.read_var_u32())
1754 }
1755}
1756
1757impl fmt::Debug for BrTable<'_> {
1758 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1759 let mut f: DebugStruct<'_, '_> = f.debug_struct(name:"BrTable");
1760 f.field(name:"count", &self.cnt);
1761 f.field(name:"default", &self.default);
1762 match self.targets().collect::<Result<Vec<_>>>() {
1763 Ok(targets: Vec) => {
1764 f.field(name:"targets", &targets);
1765 }
1766 Err(_) => {
1767 f.field(name:"reader", &self.reader);
1768 }
1769 }
1770 f.finish()
1771 }
1772}
1773
1774/// A factory to construct [`Operator`] instances via the [`VisitOperator`] trait.
1775struct OperatorFactory<'a> {
1776 marker: core::marker::PhantomData<fn() -> &'a ()>,
1777}
1778
1779impl<'a> OperatorFactory<'a> {
1780 /// Creates a new [`OperatorFactory`].
1781 fn new() -> Self {
1782 Self {
1783 marker: core::marker::PhantomData,
1784 }
1785 }
1786}
1787
1788macro_rules! define_visit_operator {
1789 ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*))*) => {
1790 $(
1791 fn $visit(&mut self $($(,$arg: $argty)*)?) -> Operator<'a> {
1792 Operator::$op $({ $($arg),* })?
1793 }
1794 )*
1795 }
1796}
1797
1798impl<'a> VisitOperator<'a> for OperatorFactory<'a> {
1799 type Output = Operator<'a>;
1800
1801 #[cfg(feature = "simd")]
1802 fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> {
1803 Some(self)
1804 }
1805
1806 crate::for_each_visit_operator!(define_visit_operator);
1807}
1808
1809#[cfg(feature = "simd")]
1810impl<'a> VisitSimdOperator<'a> for OperatorFactory<'a> {
1811 crate::for_each_visit_simd_operator!(define_visit_operator);
1812}
1813
1814/// Iterator returned from [`BinaryReader::read_iter`].
1815pub struct BinaryReaderIter<'a, 'me, T: FromReader<'a>> {
1816 remaining: usize,
1817 pub(crate) reader: &'me mut BinaryReader<'a>,
1818 _marker: marker::PhantomData<T>,
1819}
1820
1821impl<'a, T> Iterator for BinaryReaderIter<'a, '_, T>
1822where
1823 T: FromReader<'a>,
1824{
1825 type Item = Result<T>;
1826
1827 fn next(&mut self) -> Option<Result<T>> {
1828 if self.remaining == 0 {
1829 None
1830 } else {
1831 let ret: Result = self.reader.read::<T>();
1832 if ret.is_err() {
1833 self.remaining = 0;
1834 } else {
1835 self.remaining -= 1;
1836 }
1837 Some(ret)
1838 }
1839 }
1840
1841 fn size_hint(&self) -> (usize, Option<usize>) {
1842 (self.remaining, Some(self.remaining))
1843 }
1844}
1845
1846impl<'a, T> Drop for BinaryReaderIter<'a, '_, T>
1847where
1848 T: FromReader<'a>,
1849{
1850 fn drop(&mut self) {
1851 while self.next().is_some() {
1852 // ...
1853 }
1854 }
1855}
1856