Repository: bytecodealliance/wasm-tools
Pull request #1635 (2024-06-24 18:42:58)

Limit component model flags to 32
This commit is an attempt to explore the design space of WebAssembly/component-model#370. This limits, by default, the number of flags in a component model type to 32 by default. The hope of this issue is to be able to ratchet the maximum number of flags to make it easier on bindings generators to not need to work with arbitrary numbers of flags. The secondary hope is that we can ratchet flags straight to 32 instead of 64 due to it being unlikely that more than 32 flags are in use. Once this percolates there can then be a separate feature for enabling 33-64 flags.


Patch:
diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs
index 72e0034b..08e37da2 100644
--- a/crates/wasm-encoder/src/component/types.rs
+++ b/crates/wasm-encoder/src/component/types.rs
@@ -527,27 +527,6 @@ impl Encode for PrimitiveValType {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::PrimitiveValType> for PrimitiveValType {
-    fn from(ty: wasmparser::PrimitiveValType) -> Self {
-        match ty {
-            wasmparser::PrimitiveValType::Bool => PrimitiveValType::Bool,
-            wasmparser::PrimitiveValType::S8 => PrimitiveValType::S8,
-            wasmparser::PrimitiveValType::U8 => PrimitiveValType::U8,
-            wasmparser::PrimitiveValType::S16 => PrimitiveValType::S16,
-            wasmparser::PrimitiveValType::U16 => PrimitiveValType::U16,
-            wasmparser::PrimitiveValType::S32 => PrimitiveValType::S32,
-            wasmparser::PrimitiveValType::U32 => PrimitiveValType::U32,
-            wasmparser::PrimitiveValType::S64 => PrimitiveValType::S64,
-            wasmparser::PrimitiveValType::U64 => PrimitiveValType::U64,
-            wasmparser::PrimitiveValType::F32 => PrimitiveValType::F32,
-            wasmparser::PrimitiveValType::F64 => PrimitiveValType::F64,
-            wasmparser::PrimitiveValType::Char => PrimitiveValType::Char,
-            wasmparser::PrimitiveValType::String => PrimitiveValType::String,
-        }
-    }
-}
-
 /// Represents a component value type.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ComponentValType {
diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs
index 7bee3597..12a4eae2 100644
--- a/crates/wasm-encoder/src/core/code.rs
+++ b/crates/wasm-encoder/src/core/code.rs
@@ -103,30 +103,6 @@ impl CodeSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the code to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::CodeSectionReader<'_>,
-    ) -> wasmparser::Result<&mut Self> {
-        for code in section {
-            self.parse(code?)?;
-        }
-        Ok(self)
-    }
-
-    /// Parses a single [`wasmparser::Code`] and adds it to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(&mut self, func: wasmparser::FunctionBody<'_>) -> wasmparser::Result<&mut Self> {
-        let mut f = Function::new_parsed_locals(&func)?;
-        let mut reader = func.get_operators_reader()?;
-        while !reader.eof() {
-            f.parse(&mut reader)?;
-        }
-        Ok(self.function(&f))
-    }
 }
 
 impl Encode for CodeSection {
@@ -238,18 +214,6 @@ impl Function {
         Function::new(locals_collected)
     }
 
-    /// Create a new [`Function`] by parsing the locals declarations from the
-    /// provided [`wasmparser::FunctionBody`].
-    #[cfg(feature = "wasmparser")]
-    pub fn new_parsed_locals(func: &wasmparser::FunctionBody<'_>) -> wasmparser::Result<Self> {
-        let mut locals = Vec::new();
-        for pair in func.get_locals_reader()? {
-            let (cnt, ty) = pair?;
-            locals.push((cnt, ty.try_into().unwrap()));
-        }
-        Ok(Function::new(locals))
-    }
-
     /// Write an instruction into this function body.
     pub fn instruction(&mut self, instruction: &Instruction) -> &mut Self {
         instruction.encode(&mut self.bytes);
@@ -312,15 +276,6 @@ impl Function {
     pub fn into_raw_body(self) -> Vec<u8> {
         self.bytes
     }
-
-    /// Parses a single instruction from `reader` and adds it to `self`.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(
-        &mut self,
-        reader: &mut wasmparser::OperatorsReader<'_>,
-    ) -> wasmparser::Result<&mut Self> {
-        Ok(self.instruction(&reader.read()?.try_into().unwrap()))
-    }
 }
 
 impl Encode for Function {
@@ -360,17 +315,6 @@ impl Encode for MemArg {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::MemArg> for MemArg {
-    fn from(arg: wasmparser::MemArg) -> MemArg {
-        MemArg {
-            offset: arg.offset,
-            align: arg.align.into(),
-            memory_index: arg.memory,
-        }
-    }
-}
-
 /// The memory ordering for atomic instructions.
 ///
 /// For an in-depth explanation of memory orderings, see the C++ documentation
@@ -399,16 +343,6 @@ impl Encode for Ordering {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::Ordering> for Ordering {
-    fn from(arg: wasmparser::Ordering) -> Ordering {
-        match arg {
-            wasmparser::Ordering::SeqCst => Ordering::SeqCst,
-            wasmparser::Ordering::AcqRel => Ordering::AcqRel,
-        }
-    }
-}
-
 /// Describe an unchecked SIMD lane index.
 pub type Lane = u8;
 
@@ -433,18 +367,6 @@ impl Encode for BlockType {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::BlockType> for BlockType {
-    type Error = ();
-    fn try_from(arg: wasmparser::BlockType) -> Result<BlockType, ()> {
-        match arg {
-            wasmparser::BlockType::Empty => Ok(BlockType::Empty),
-            wasmparser::BlockType::FuncType(n) => Ok(BlockType::FunctionType(n)),
-            wasmparser::BlockType::Type(t) => Ok(BlockType::Result(t.try_into()?)),
-        }
-    }
-}
-
 /// WebAssembly instructions.
 #[derive(Clone, Debug)]
 #[non_exhaustive]
@@ -3401,64 +3323,6 @@ impl Encode for Instruction<'_> {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::Operator<'_>> for Instruction<'_> {
-    type Error = ();
-
-    fn try_from(arg: wasmparser::Operator<'_>) -> Result<Self, ()> {
-        use Instruction::*;
-
-        macro_rules! define_match {
-            ($(@$p:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
-                match arg {
-                    $(
-                        wasmparser::Operator::$op $({ $($arg),* })? => {
-                            $(
-                                $(let $arg = define_match!(map $arg $arg);)*
-                            )?
-                            Ok(define_match!(mk $op $($($arg)*)?))
-                        }
-                    )*
-                }
-            };
-
-            // No-payload instructions are named the same in wasmparser as they are in
-            // wasm-encoder
-            (mk $op:ident) => ($op);
-
-            // Instructions which need "special care" to map from wasmparser to
-            // wasm-encoder
-            (mk BrTable $arg:ident) => ({BrTable($arg.0, $arg.1)});
-            (mk TryTable $arg:ident) => ({TryTable($arg.0, $arg.1)});
-
-            // Catch-all for the translation of one payload argument which is typically
-            // represented as a tuple-enum in wasm-encoder.
-            (mk $op:ident $arg:ident) => ($op($arg));
-
-            // Catch-all of everything else where the wasmparser fields are simply
-            // translated to wasm-encoder fields.
-            (mk $op:ident $($arg:ident)*) => ($op { $($arg),* });
-
-            // Special-case BrTable/TryTable conversion of arguments.
-            (map $arg:ident targets) => ((
-                $arg.targets().map(|i| i.unwrap()).collect::<Vec<_>>().into(),
-                $arg.default(),
-            ));
-            (map $arg:ident try_table) => ((
-                $arg.ty.try_into().unwrap(),
-                $arg.catches.into_iter().map(|i| i.into()).collect::<Vec<_>>().into(),
-            ));
-
-            // Everything else is converted with `TryFrom`/`From`. Note that the
-            // fallibility here has to do with how indexes are represented in
-            // `wasmparser` which we know when reading directly we'll never hit the
-            // erroneous cases here, hence the unwrap.
-            (map $arg:ident $other:ident) => {$other.try_into().unwrap()};
-        }
-        wasmparser::for_each_operator!(define_match)
-    }
-}
-
 #[derive(Clone, Debug)]
 #[allow(missing_docs)]
 pub enum Catch {
@@ -3493,18 +3357,6 @@ impl Encode for Catch {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::Catch> for Catch {
-    fn from(arg: wasmparser::Catch) -> Catch {
-        match arg {
-            wasmparser::Catch::One { tag, label } => Catch::One { tag, label },
-            wasmparser::Catch::OneRef { tag, label } => Catch::OneRef { tag, label },
-            wasmparser::Catch::All { label } => Catch::All { label },
-            wasmparser::Catch::AllRef { label } => Catch::AllRef { label },
-        }
-    }
-}
-
 /// A constant expression.
 ///
 /// Usable in contexts such as offsets or initializers.
@@ -3669,101 +3521,6 @@ impl Encode for ConstExpr {
     }
 }
 
-/// An error when converting a `wasmparser::ConstExpr` into a
-/// `wasm_encoder::ConstExpr`.
-#[cfg(feature = "wasmparser")]
-#[derive(Debug)]
-pub enum ConstExprConversionError {
-    /// There was an error when parsing the const expression.
-    ParseError(wasmparser::BinaryReaderError),
-
-    /// The const expression is invalid: not actually constant or something like
-    /// that.
-    Invalid,
-
-    /// There was a type reference that was canonicalized and no longer
-    /// references an index into a module's types space, so we cannot encode it
-    /// into a Wasm binary again.
-    CanonicalizedTypeReference,
-}
-
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::BinaryReaderError> for ConstExprConversionError {
-    fn from(err: wasmparser::BinaryReaderError) -> ConstExprConversionError {
-        ConstExprConversionError::ParseError(err)
-    }
-}
-
-#[cfg(feature = "wasmparser")]
-impl std::fmt::Display for ConstExprConversionError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::ParseError(_e) => {
-                write!(f, "There was an error when parsing the const expression")
-            }
-            Self::Invalid => write!(f, "The const expression was invalid"),
-            Self::CanonicalizedTypeReference => write!(
-                f,
-                "There was a canonicalized type reference without type index information"
-            ),
-        }
-    }
-}
-
-#[cfg(feature = "wasmparser")]
-impl std::error::Error for ConstExprConversionError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        match self {
-            Self::ParseError(e) => Some(e),
-            Self::Invalid | Self::CanonicalizedTypeReference => None,
-        }
-    }
-}
-
-#[cfg(feature = "wasmparser")]
-impl<'a> TryFrom<wasmparser::ConstExpr<'a>> for ConstExpr {
-    type Error = ConstExprConversionError;
-
-    fn try_from(const_expr: wasmparser::ConstExpr) -> Result<Self, Self::Error> {
-        let mut ops = const_expr.get_operators_reader().into_iter();
-
-        let result = match ops.next() {
-            Some(Ok(wasmparser::Operator::I32Const { value })) => ConstExpr::i32_const(value),
-            Some(Ok(wasmparser::Operator::I64Const { value })) => ConstExpr::i64_const(value),
-            Some(Ok(wasmparser::Operator::F32Const { value })) => {
-                ConstExpr::f32_const(f32::from_bits(value.bits()))
-            }
-            Some(Ok(wasmparser::Operator::F64Const { value })) => {
-                ConstExpr::f64_const(f64::from_bits(value.bits()))
-            }
-            Some(Ok(wasmparser::Operator::V128Const { value })) => {
-                ConstExpr::v128_const(i128::from_le_bytes(*value.bytes()))
-            }
-            Some(Ok(wasmparser::Operator::RefNull { hty })) => ConstExpr::ref_null(
-                HeapType::try_from(hty)
-                    .map_err(|_| ConstExprConversionError::CanonicalizedTypeReference)?,
-            ),
-            Some(Ok(wasmparser::Operator::RefFunc { function_index })) => {
-                ConstExpr::ref_func(function_index)
-            }
-            Some(Ok(wasmparser::Operator::GlobalGet { global_index })) => {
-                ConstExpr::global_get(global_index)
-            }
-
-            // TODO: support the extended-const proposal.
-            Some(Ok(_op)) => return Err(ConstExprConversionError::Invalid),
-
-            Some(Err(e)) => return Err(ConstExprConversionError::ParseError(e)),
-            None => return Err(ConstExprConversionError::Invalid),
-        };
-
-        match (ops.next(), ops.next()) {
-            (Some(Ok(wasmparser::Operator::End)), None) => Ok(result),
-            _ => Err(ConstExprConversionError::Invalid),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     #[test]
diff --git a/crates/wasm-encoder/src/core/custom.rs b/crates/wasm-encoder/src/core/custom.rs
index 75cae490..870ee626 100644
--- a/crates/wasm-encoder/src/core/custom.rs
+++ b/crates/wasm-encoder/src/core/custom.rs
@@ -44,16 +44,6 @@ impl Section for RawCustomSection<'_> {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl<'a> From<wasmparser::CustomSectionReader<'a>> for CustomSection<'a> {
-    fn from(section: wasmparser::CustomSectionReader<'a>) -> Self {
-        CustomSection {
-            data: section.data().into(),
-            name: section.name().into(),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/crates/wasm-encoder/src/core/data.rs b/crates/wasm-encoder/src/core/data.rs
index 7f8dd795..6f408bef 100644
--- a/crates/wasm-encoder/src/core/data.rs
+++ b/crates/wasm-encoder/src/core/data.rs
@@ -151,38 +151,6 @@ impl DataSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the data to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::DataSectionReader<'_>,
-    ) -> Result<&mut Self, crate::ConstExprConversionError> {
-        for data in section {
-            self.parse(data?)?;
-        }
-        Ok(self)
-    }
-
-    /// Parses a single [`wasmparser::Data`] and adds it to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(
-        &mut self,
-        data: wasmparser::Data<'_>,
-    ) -> Result<&mut Self, crate::ConstExprConversionError> {
-        match data.kind {
-            wasmparser::DataKind::Active {
-                memory_index,
-                offset_expr,
-            } => Ok(self.active(
-                memory_index,
-                &ConstExpr::try_from(offset_expr)?,
-                data.data.iter().copied(),
-            )),
-            wasmparser::DataKind::Passive => Ok(self.passive(data.data.iter().copied())),
-        }
-    }
 }
 
 impl Encode for DataSection {
diff --git a/crates/wasm-encoder/src/core/elements.rs b/crates/wasm-encoder/src/core/elements.rs
index 8d24c4e3..28a1031e 100644
--- a/crates/wasm-encoder/src/core/elements.rs
+++ b/crates/wasm-encoder/src/core/elements.rs
@@ -206,54 +206,6 @@ impl ElementSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the elements to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::ElementSectionReader<'_>,
-    ) -> Result<&mut Self, crate::ConstExprConversionError> {
-        for element in section {
-            self.parse(element?)?;
-        }
-        Ok(self)
-    }
-
-    /// Parses the single [`wasmparser::Element`] provided and adds it to this
-    /// section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(
-        &mut self,
-        element: wasmparser::Element<'_>,
-    ) -> Result<&mut Self, crate::ConstExprConversionError> {
-        let mut funcs;
-        let mut exprs;
-        let elements = match element.items {
-            wasmparser::ElementItems::Functions(f) => {
-                funcs = Vec::new();
-                for func in f {
-                    funcs.push(func?);
-                }
-                Elements::Functions(&funcs)
-            }
-            wasmparser::ElementItems::Expressions(ty, e) => {
-                exprs = Vec::new();
-                for expr in e {
-                    exprs.push(ConstExpr::try_from(expr?)?);
-                }
-                Elements::Expressions(ty.try_into().unwrap(), &exprs)
-            }
-        };
-        match element.kind {
-            wasmparser::ElementKind::Active {
-                table_index,
-                offset_expr,
-            } => Ok(self.active(table_index, &ConstExpr::try_from(offset_expr)?, elements)),
-            wasmparser::ElementKind::Passive => Ok(self.passive(elements)),
-            wasmparser::ElementKind::Declared => Ok(self.declared(elements)),
-        }
-    }
 }
 
 impl Encode for ElementSection {
diff --git a/crates/wasm-encoder/src/core/exports.rs b/crates/wasm-encoder/src/core/exports.rs
index 7b06fabc..36c78963 100644
--- a/crates/wasm-encoder/src/core/exports.rs
+++ b/crates/wasm-encoder/src/core/exports.rs
@@ -25,19 +25,6 @@ impl Encode for ExportKind {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::ExternalKind> for ExportKind {
-    fn from(external_kind: wasmparser::ExternalKind) -> Self {
-        match external_kind {
-            wasmparser::ExternalKind::Func => ExportKind::Func,
-            wasmparser::ExternalKind::Table => ExportKind::Table,
-            wasmparser::ExternalKind::Memory => ExportKind::Memory,
-            wasmparser::ExternalKind::Global => ExportKind::Global,
-            wasmparser::ExternalKind::Tag => ExportKind::Tag,
-        }
-    }
-}
-
 /// An encoder for the export section of WebAssembly module.
 ///
 /// # Example
@@ -83,26 +70,6 @@ impl ExportSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the exports to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::ExportSectionReader<'_>,
-    ) -> wasmparser::Result<&mut Self> {
-        for export in section {
-            self.parse(export?);
-        }
-        Ok(self)
-    }
-
-    /// Parses the single [`wasmparser::Export`] provided and adds it to this
-    /// section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(&mut self, export: wasmparser::Export<'_>) -> &mut Self {
-        self.export(export.name, export.kind.into(), export.index)
-    }
 }
 
 impl Encode for ExportSection {
diff --git a/crates/wasm-encoder/src/core/functions.rs b/crates/wasm-encoder/src/core/functions.rs
index 3cc053ba..e21d8c10 100644
--- a/crates/wasm-encoder/src/core/functions.rs
+++ b/crates/wasm-encoder/src/core/functions.rs
@@ -48,19 +48,6 @@ impl FunctionSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the functions to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::FunctionSectionReader<'_>,
-    ) -> wasmparser::Result<&mut Self> {
-        for func in section {
-            self.function(func?);
-        }
-        Ok(self)
-    }
 }
 
 impl Encode for FunctionSection {
diff --git a/crates/wasm-encoder/src/core/globals.rs b/crates/wasm-encoder/src/core/globals.rs
index f208f63f..dcd96ac3 100644
--- a/crates/wasm-encoder/src/core/globals.rs
+++ b/crates/wasm-encoder/src/core/globals.rs
@@ -60,30 +60,6 @@ impl GlobalSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the globals to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::GlobalSectionReader<'_>,
-    ) -> Result<&mut Self, crate::ConstExprConversionError> {
-        for global in section {
-            self.parse(global?)?;
-        }
-        Ok(self)
-    }
-
-    /// Parses the single [`wasmparser::Global`] provided and adds it to this
-    /// section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(
-        &mut self,
-        global: wasmparser::Global<'_>,
-    ) -> Result<&mut Self, crate::ConstExprConversionError> {
-        self.global(global.ty.try_into().unwrap(), &global.init_expr.try_into()?);
-        Ok(self)
-    }
 }
 
 impl Encode for GlobalSection {
@@ -122,15 +98,3 @@ impl Encode for GlobalType {
         sink.push(flag);
     }
 }
-
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::GlobalType> for GlobalType {
-    type Error = ();
-    fn try_from(global_ty: wasmparser::GlobalType) -> Result<Self, Self::Error> {
-        Ok(GlobalType {
-            val_type: global_ty.content_type.try_into()?,
-            mutable: global_ty.mutable,
-            shared: global_ty.shared,
-        })
-    }
-}
diff --git a/crates/wasm-encoder/src/core/imports.rs b/crates/wasm-encoder/src/core/imports.rs
index 5eac839c..b3a0879d 100644
--- a/crates/wasm-encoder/src/core/imports.rs
+++ b/crates/wasm-encoder/src/core/imports.rs
@@ -73,20 +73,6 @@ impl From<TagType> for EntityType {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::TypeRef> for EntityType {
-    type Error = ();
-    fn try_from(type_ref: wasmparser::TypeRef) -> Result<Self, Self::Error> {
-        Ok(match type_ref {
-            wasmparser::TypeRef::Func(i) => EntityType::Function(i),
-            wasmparser::TypeRef::Table(t) => EntityType::Table(t.try_into()?),
-            wasmparser::TypeRef::Memory(m) => EntityType::Memory(m.into()),
-            wasmparser::TypeRef::Global(g) => EntityType::Global(g.try_into()?),
-            wasmparser::TypeRef::Tag(t) => EntityType::Tag(t.into()),
-        })
-    }
-}
-
 /// An encoder for the import section of WebAssembly modules.
 ///
 /// # Example
@@ -142,31 +128,6 @@ impl ImportSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the imports to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::ImportSectionReader<'_>,
-    ) -> wasmparser::Result<&mut Self> {
-        for import in section {
-            self.parse(import?);
-        }
-        Ok(self)
-    }
-
-    /// Parses the single [`wasmparser::Import`] provided and adds it to this
-    /// section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(&mut self, import: wasmparser::Import<'_>) -> &mut Self {
-        self.import(
-            import.module,
-            import.name,
-            EntityType::try_from(import.ty).unwrap(),
-        );
-        self
-    }
 }
 
 impl Encode for ImportSection {
diff --git a/crates/wasm-encoder/src/core/memories.rs b/crates/wasm-encoder/src/core/memories.rs
index b3942dfa..d0c9087f 100644
--- a/crates/wasm-encoder/src/core/memories.rs
+++ b/crates/wasm-encoder/src/core/memories.rs
@@ -51,20 +51,6 @@ impl MemorySection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the memories to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::MemorySectionReader<'_>,
-    ) -> wasmparser::Result<&mut Self> {
-        for memory in section {
-            let memory = memory?;
-            self.memory(memory.into());
-        }
-        Ok(self)
-    }
 }
 
 impl Encode for MemorySection {
@@ -127,16 +113,3 @@ impl Encode for MemoryType {
         }
     }
 }
-
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::MemoryType> for MemoryType {
-    fn from(memory_ty: wasmparser::MemoryType) -> Self {
-        MemoryType {
-            minimum: memory_ty.initial,
-            maximum: memory_ty.maximum,
-            memory64: memory_ty.memory64,
-            shared: memory_ty.shared,
-            page_size_log2: memory_ty.page_size_log2,
-        }
-    }
-}
diff --git a/crates/wasm-encoder/src/core/tables.rs b/crates/wasm-encoder/src/core/tables.rs
index 24bfe03a..6b35915b 100644
--- a/crates/wasm-encoder/src/core/tables.rs
+++ b/crates/wasm-encoder/src/core/tables.rs
@@ -62,37 +62,6 @@ impl TableSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the tables to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::TableSectionReader<'_>,
-    ) -> Result<&mut Self, crate::ConstExprConversionError> {
-        for table in section {
-            self.parse(table?)?;
-        }
-        Ok(self)
-    }
-
-    /// Parses a single [`wasmparser::Table`] and adds it to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(
-        &mut self,
-        table: wasmparser::Table<'_>,
-    ) -> Result<&mut Self, crate::ConstExprConversionError> {
-        let ty = table.ty.try_into().unwrap();
-        match table.init {
-            wasmparser::TableInit::RefNull => {
-                self.table(ty);
-            }
-            wasmparser::TableInit::Expr(e) => {
-                self.table_with_init(ty, &e.try_into()?);
-            }
-        }
-        Ok(self)
-    }
 }
 
 impl Encode for TableSection {
@@ -150,16 +119,3 @@ impl Encode for TableType {
         }
     }
 }
-
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::TableType> for TableType {
-    type Error = ();
-    fn try_from(table_ty: wasmparser::TableType) -> Result<Self, Self::Error> {
-        Ok(TableType {
-            element_type: table_ty.element_type.try_into()?,
-            minimum: table_ty.initial,
-            maximum: table_ty.maximum,
-            table64: table_ty.table64,
-        })
-    }
-}
diff --git a/crates/wasm-encoder/src/core/tags.rs b/crates/wasm-encoder/src/core/tags.rs
index 2d6a88d9..413055f2 100644
--- a/crates/wasm-encoder/src/core/tags.rs
+++ b/crates/wasm-encoder/src/core/tags.rs
@@ -46,20 +46,6 @@ impl TagSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the tags to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::TagSectionReader<'_>,
-    ) -> wasmparser::Result<&mut Self> {
-        for tag in section {
-            let tag = tag?;
-            self.tag(tag.into());
-        }
-        Ok(self)
-    }
 }
 
 impl Encode for TagSection {
@@ -82,15 +68,6 @@ pub enum TagKind {
     Exception = 0x0,
 }
 
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::TagKind> for TagKind {
-    fn from(kind: wasmparser::TagKind) -> Self {
-        match kind {
-            wasmparser::TagKind::Exception => TagKind::Exception,
-        }
-    }
-}
-
 /// A tag's type.
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub struct TagType {
@@ -106,13 +83,3 @@ impl Encode for TagType {
         self.func_type_idx.encode(sink);
     }
 }
-
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::TagType> for TagType {
-    fn from(tag_ty: wasmparser::TagType) -> Self {
-        TagType {
-            kind: tag_ty.kind.into(),
-            func_type_idx: tag_ty.func_type_idx,
-        }
-    }
-}
diff --git a/crates/wasm-encoder/src/core/types.rs b/crates/wasm-encoder/src/core/types.rs
index 0f53326b..de6705f9 100644
--- a/crates/wasm-encoder/src/core/types.rs
+++ b/crates/wasm-encoder/src/core/types.rs
@@ -23,22 +23,6 @@ impl Encode for SubType {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::SubType> for SubType {
-    type Error = ();
-
-    fn try_from(sub_ty: wasmparser::SubType) -> Result<Self, Self::Error> {
-        Ok(SubType {
-            is_final: sub_ty.is_final,
-            supertype_idx: sub_ty
-                .supertype_idx
-                .map(|i| i.as_module_index().ok_or(()))
-                .transpose()?,
-            composite_type: sub_ty.composite_type.try_into()?,
-        })
-    }
-}
-
 /// Represents a composite type in a WebAssembly module.
 #[derive(Debug, Clone)]
 pub enum CompositeType {
@@ -68,18 +52,6 @@ impl Encode for CompositeType {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::CompositeType> for CompositeType {
-    type Error = ();
-    fn try_from(composite_ty: wasmparser::CompositeType) -> Result<Self, Self::Error> {
-        Ok(match composite_ty {
-            wasmparser::CompositeType::Func(f) => CompositeType::Func(f.try_into()?),
-            wasmparser::CompositeType::Array(a) => CompositeType::Array(a.try_into()?),
-            wasmparser::CompositeType::Struct(s) => CompositeType::Struct(s.try_into()?),
-        })
-    }
-}
-
 /// Represents a type of a function in a WebAssembly module.
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct FuncType {
@@ -89,30 +61,10 @@ pub struct FuncType {
     len_params: usize,
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::FuncType> for FuncType {
-    type Error = ();
-    fn try_from(func_ty: wasmparser::FuncType) -> Result<Self, Self::Error> {
-        let mut buf = Vec::with_capacity(func_ty.params().len() + func_ty.results().len());
-        for ty in func_ty.params().iter().chain(func_ty.results()).copied() {
-            buf.push(ty.try_into()?);
-        }
-        Ok(FuncType::from_parts(buf.into(), func_ty.params().len()))
-    }
-}
-
 /// Represents a type of an array in a WebAssembly module.
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
 pub struct ArrayType(pub FieldType);
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::ArrayType> for ArrayType {
-    type Error = ();
-    fn try_from(array_ty: wasmparser::ArrayType) -> Result<Self, Self::Error> {
-        Ok(ArrayType(array_ty.0.try_into()?))
-    }
-}
-
 /// Represents a type of a struct in a WebAssembly module.
 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
 pub struct StructType {
@@ -120,21 +72,6 @@ pub struct StructType {
     pub fields: Box<[FieldType]>,
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::StructType> for StructType {
-    type Error = ();
-    fn try_from(struct_ty: wasmparser::StructType) -> Result<Self, Self::Error> {
-        Ok(StructType {
-            fields: struct_ty
-                .fields
-                .iter()
-                .cloned()
-                .map(TryInto::try_into)
-                .collect::<Result<_, _>>()?,
-        })
-    }
-}
-
 /// Field type in composite types (structs, arrays).
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct FieldType {
@@ -144,17 +81,6 @@ pub struct FieldType {
     pub mutable: bool,
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::FieldType> for FieldType {
-    type Error = ();
-    fn try_from(field_ty: wasmparser::FieldType) -> Result<Self, Self::Error> {
-        Ok(FieldType {
-            element_type: field_ty.element_type.try_into()?,
-            mutable: field_ty.mutable,
-        })
-    }
-}
-
 /// Storage type for composite type fields.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub enum StorageType {
@@ -166,18 +92,6 @@ pub enum StorageType {
     Val(ValType),
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::StorageType> for StorageType {
-    type Error = ();
-    fn try_from(storage_ty: wasmparser::StorageType) -> Result<Self, Self::Error> {
-        Ok(match storage_ty {
-            wasmparser::StorageType::I8 => StorageType::I8,
-            wasmparser::StorageType::I16 => StorageType::I16,
-            wasmparser::StorageType::Val(v) => StorageType::Val(v.try_into()?),
-        })
-    }
-}
-
 impl StorageType {
     /// Is this storage type defaultable?
     pub fn is_defaultable(&self) -> bool {
@@ -216,21 +130,6 @@ pub enum ValType {
     Ref(RefType),
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::ValType> for ValType {
-    type Error = ();
-    fn try_from(val_ty: wasmparser::ValType) -> Result<Self, Self::Error> {
-        Ok(match val_ty {
-            wasmparser::ValType::I32 => ValType::I32,
-            wasmparser::ValType::I64 => ValType::I64,
-            wasmparser::ValType::F32 => ValType::F32,
-            wasmparser::ValType::F64 => ValType::F64,
-            wasmparser::ValType::V128 => ValType::V128,
-            wasmparser::ValType::Ref(r) => ValType::Ref(r.try_into()?),
-        })
-    }
-}
-
 impl ValType {
     /// Is this a numeric value type?
     pub fn is_numeric(&self) -> bool {
@@ -442,18 +341,6 @@ impl Encode for RefType {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::RefType> for RefType {
-    type Error = ();
-
-    fn try_from(ref_type: wasmparser::RefType) -> Result<Self, Self::Error> {
-        Ok(RefType {
-            nullable: ref_type.is_nullable(),
-            heap_type: ref_type.heap_type().try_into()?,
-        })
-    }
-}
-
 impl From<RefType> for ValType {
     fn from(ty: RefType) -> ValType {
         ValType::Ref(ty)
@@ -517,21 +404,6 @@ impl Encode for HeapType {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl TryFrom<wasmparser::HeapType> for HeapType {
-    type Error = ();
-
-    fn try_from(heap_type: wasmparser::HeapType) -> Result<Self, Self::Error> {
-        Ok(match heap_type {
-            wasmparser::HeapType::Concrete(i) => HeapType::Concrete(i.as_module_index().ok_or(())?),
-            wasmparser::HeapType::Abstract { shared, ty } => HeapType::Abstract {
-                shared,
-                ty: ty.into(),
-            },
-        })
-    }
-}
-
 /// An abstract heap type.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub enum AbstractHeapType {
@@ -607,27 +479,6 @@ impl Encode for AbstractHeapType {
     }
 }
 
-#[cfg(feature = "wasmparser")]
-impl From<wasmparser::AbstractHeapType> for AbstractHeapType {
-    fn from(value: wasmparser::AbstractHeapType) -> Self {
-        use wasmparser::AbstractHeapType::*;
-        match value {
-            Func => AbstractHeapType::Func,
-            Extern => AbstractHeapType::Extern,
-            Any => AbstractHeapType::Any,
-            None => AbstractHeapType::None,
-            NoExtern => AbstractHeapType::NoExtern,
-            NoFunc => AbstractHeapType::NoFunc,
-            Eq => AbstractHeapType::Eq,
-            Struct => AbstractHeapType::Struct,
-            Array => AbstractHeapType::Array,
-            I31 => AbstractHeapType::I31,
-            Exn => AbstractHeapType::Exn,
-            NoExn => AbstractHeapType::NoExn,
-        }
-    }
-}
-
 /// An encoder for the type section of WebAssembly modules.
 ///
 /// # Example
@@ -679,6 +530,17 @@ impl TypeSection {
         self
     }
 
+    /// Define a function type in this type section.
+    pub fn func_type(&mut self, ty: &FuncType) -> &mut Self {
+        Self::encode_function(
+            &mut self.bytes,
+            ty.params().iter().cloned(),
+            ty.results().iter().cloned(),
+        );
+        self.num_added += 1;
+        self
+    }
+
     fn encode_function<P, R>(sink: &mut Vec<u8>, params: P, results: R)
     where
         P: IntoIterator<Item = ValType>,
@@ -757,31 +619,6 @@ impl TypeSection {
         self.num_added += 1;
         self
     }
-
-    /// Parses the input `section` given from the `wasmparser` crate and adds
-    /// all the types to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse_section(
-        &mut self,
-        section: wasmparser::TypeSectionReader<'_>,
-    ) -> wasmparser::Result<&mut Self> {
-        for rec_group in section {
-            self.parse(rec_group?);
-        }
-        Ok(self)
-    }
-
-    /// Parses a single [`wasmparser::RecGroup`] and adds it to this section.
-    #[cfg(feature = "wasmparser")]
-    pub fn parse(&mut self, rec_group: wasmparser::RecGroup) -> &mut Self {
-        if rec_group.is_explicit_rec_group() {
-            self.rec(rec_group.into_types().map(|t| t.try_into().unwrap()));
-        } else {
-            let ty = rec_group.into_types().next().unwrap();
-            self.subtype(&SubType::try_from(ty).unwrap());
-        }
-        self
-    }
 }
 
 impl Encode for TypeSection {
diff --git a/crates/wasm-encoder/src/lib.rs b/crates/wasm-encoder/src/lib.rs
index ae30a643..756bf517 100644
--- a/crates/wasm-encoder/src/lib.rs
+++ b/crates/wasm-encoder/src/lib.rs
@@ -74,6 +74,8 @@
 mod component;
 mod core;
 mod raw;
+#[cfg(feature = "wasmparser")]
+pub mod reencode;
 
 pub use self::component::*;
 pub use self::core::*;
diff --git a/crates/wasm-encoder/src/reencode.rs b/crates/wasm-encoder/src/reencode.rs
new file mode 100644
index 00000000..8624b819
--- /dev/null
+++ b/crates/wasm-encoder/src/reencode.rs
@@ -0,0 +1,1804 @@
+//! Conversions from `wasmparser` to `wasm-encoder` to [`Reencode`] parsed wasm.
+//!
+//! The [`RoundtripReencoder`] allows encoding identical wasm to the parsed
+//! input.
+
+use std::convert::Infallible;
+
+#[allow(missing_docs)] // FIXME
+pub trait Reencode {
+    type Error;
+
+    fn data_index(&mut self, data: u32) -> u32 {
+        utils::data_index(self, data)
+    }
+
+    fn element_index(&mut self, element: u32) -> u32 {
+        utils::element_index(self, element)
+    }
+
+    fn function_index(&mut self, func: u32) -> u32 {
+        utils::function_index(self, func)
+    }
+
+    fn global_index(&mut self, global: u32) -> u32 {
+        utils::global_index(self, global)
+    }
+
+    fn memory_index(&mut self, memory: u32) -> u32 {
+        utils::memory_index(self, memory)
+    }
+
+    fn table_index(&mut self, table: u32) -> u32 {
+        utils::table_index(self, table)
+    }
+
+    fn tag_index(&mut self, tag: u32) -> u32 {
+        utils::tag_index(self, tag)
+    }
+
+    fn type_index(&mut self, ty: u32) -> u32 {
+        utils::type_index(self, ty)
+    }
+
+    fn abstract_heap_type(
+        &mut self,
+        value: wasmparser::AbstractHeapType,
+    ) -> crate::AbstractHeapType {
+        utils::abstract_heap_type(self, value)
+    }
+
+    fn array_type(
+        &mut self,
+        array_ty: wasmparser::ArrayType,
+    ) -> Result<crate::ArrayType, Error<Self::Error>> {
+        utils::array_type(self, array_ty)
+    }
+
+    fn block_type(
+        &mut self,
+        arg: wasmparser::BlockType,
+    ) -> Result<crate::BlockType, Error<Self::Error>> {
+        utils::block_type(self, arg)
+    }
+
+    fn component_primitive_val_type(
+        &mut self,
+        ty: wasmparser::PrimitiveValType,
+    ) -> crate::component::PrimitiveValType {
+        utils::component_primitive_val_type(self, ty)
+    }
+
+    fn const_expr(
+        &mut self,
+        const_expr: wasmparser::ConstExpr,
+    ) -> Result<crate::ConstExpr, Error<Self::Error>> {
+        utils::const_expr(self, const_expr)
+    }
+
+    fn catch(&mut self, arg: wasmparser::Catch) -> crate::Catch {
+        utils::catch(self, arg)
+    }
+
+    fn composite_type(
+        &mut self,
+        composite_ty: wasmparser::CompositeType,
+    ) -> Result<crate::CompositeType, Error<Self::Error>> {
+        utils::composite_type(self, composite_ty)
+    }
+
+    fn entity_type(
+        &mut self,
+        type_ref: wasmparser::TypeRef,
+    ) -> Result<crate::EntityType, Error<Self::Error>> {
+        utils::entity_type(self, type_ref)
+    }
+
+    fn export_kind(&mut self, external_kind: wasmparser::ExternalKind) -> crate::ExportKind {
+        utils::export_kind(self, external_kind)
+    }
+
+    fn field_type(
+        &mut self,
+        field_ty: wasmparser::FieldType,
+    ) -> Result<crate::FieldType, Error<Self::Error>> {
+        utils::field_type(self, field_ty)
+    }
+
+    fn func_type(
+        &mut self,
+        func_ty: wasmparser::FuncType,
+    ) -> Result<crate::FuncType, Error<Self::Error>> {
+        utils::func_type(self, func_ty)
+    }
+
+    fn global_type(
+        &mut self,
+        global_ty: wasmparser::GlobalType,
+    ) -> Result<crate::GlobalType, Error<Self::Error>> {
+        utils::global_type(self, global_ty)
+    }
+
+    fn heap_type(
+        &mut self,
+        heap_type: wasmparser::HeapType,
+    ) -> Result<crate::HeapType, Error<Self::Error>> {
+        utils::heap_type(self, heap_type)
+    }
+
+    fn instruction<'a>(
+        &mut self,
+        arg: wasmparser::Operator<'a>,
+    ) -> Result<crate::Instruction<'a>, Error<Self::Error>> {
+        utils::instruction(self, arg)
+    }
+
+    fn memory_type(&mut self, memory_ty: wasmparser::MemoryType) -> crate::MemoryType {
+        utils::memory_type(self, memory_ty)
+    }
+
+    fn mem_arg(&mut self, arg: wasmparser::MemArg) -> crate::MemArg {
+        utils::mem_arg(self, arg)
+    }
+
+    fn ordering(&mut self, arg: wasmparser::Ordering) -> crate::Ordering {
+        utils::ordering(self, arg)
+    }
+
+    fn ref_type(
+        &mut self,
+        ref_type: wasmparser::RefType,
+    ) -> Result<crate::RefType, Error<Self::Error>> {
+        utils::ref_type(self, ref_type)
+    }
+
+    fn storage_type(
+        &mut self,
+        storage_ty: wasmparser::StorageType,
+    ) -> Result<crate::StorageType, Error<Self::Error>> {
+        utils::storage_type(self, storage_ty)
+    }
+
+    fn struct_type(
+        &mut self,
+        struct_ty: wasmparser::StructType,
+    ) -> Result<crate::StructType, Error<Self::Error>> {
+        utils::struct_type(self, struct_ty)
+    }
+
+    fn sub_type(
+        &mut self,
+        sub_ty: wasmparser::SubType,
+    ) -> Result<crate::SubType, Error<Self::Error>> {
+        utils::sub_type(self, sub_ty)
+    }
+
+    fn table_type(
+        &mut self,
+        table_ty: wasmparser::TableType,
+    ) -> Result<crate::TableType, Error<Self::Error>> {
+        utils::table_type(self, table_ty)
+    }
+
+    fn tag_kind(&mut self, kind: wasmparser::TagKind) -> crate::TagKind {
+        utils::tag_kind(self, kind)
+    }
+
+    fn tag_type(&mut self, tag_ty: wasmparser::TagType) -> crate::TagType {
+        utils::tag_type(self, tag_ty)
+    }
+
+    fn val_type(
+        &mut self,
+        val_ty: wasmparser::ValType,
+    ) -> Result<crate::ValType, Error<Self::Error>> {
+        utils::val_type(self, val_ty)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and
+    /// adds the custom section to the `module`.
+    fn parse_custom_section(
+        &mut self,
+        module: &mut crate::Module,
+        section: wasmparser::CustomSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_custom_section(self, module, section)
+    }
+
+    /// Converts the input `section` given from the `wasmparser` crate into an
+    /// encoded custom section.
+    fn custom_section<'a>(
+        &mut self,
+        section: wasmparser::CustomSectionReader<'a>,
+    ) -> crate::CustomSection<'a> {
+        utils::custom_section(self, section)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the code to the `code` section.
+    fn parse_code_section(
+        &mut self,
+        code: &mut crate::CodeSection,
+        section: wasmparser::CodeSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_code_section(self, code, section)
+    }
+
+    /// Parses a single [`wasmparser::FunctionBody`] and adds it to the `code` section.
+    fn parse_function_body(
+        &mut self,
+        code: &mut crate::CodeSection,
+        func: wasmparser::FunctionBody<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_function_body(self, code, func)
+    }
+
+    /// Create a new [`crate::Function`] by parsing the locals declarations from the
+    /// provided [`wasmparser::FunctionBody`].
+    fn new_function_with_parsed_locals(
+        &mut self,
+        func: &wasmparser::FunctionBody<'_>,
+    ) -> Result<crate::Function, Error<Self::Error>> {
+        utils::new_function_with_parsed_locals(self, func)
+    }
+
+    /// Parses a single instruction from `reader` and adds it to `function`.
+    fn parse_instruction(
+        &mut self,
+        function: &mut crate::Function,
+        reader: &mut wasmparser::OperatorsReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_instruction(self, function, reader)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the data to the `data` section.
+    fn parse_data_section(
+        &mut self,
+        data: &mut crate::DataSection,
+        section: wasmparser::DataSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_data_section(self, data, section)
+    }
+
+    /// Parses a single [`wasmparser::Data`] and adds it to the `data` section.
+    fn parse_data(
+        &mut self,
+        data: &mut crate::DataSection,
+        datum: wasmparser::Data<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_data(self, data, datum)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the elements to the `element` section.
+    fn parse_element_section(
+        &mut self,
+        elements: &mut crate::ElementSection,
+        section: wasmparser::ElementSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_element_section(self, elements, section)
+    }
+
+    /// Parses the single [`wasmparser::Element`] provided and adds it to the
+    /// `element` section.
+    fn parse_element(
+        &mut self,
+        elements: &mut crate::ElementSection,
+        element: wasmparser::Element<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_element(self, elements, element)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the exports to the `exports` section.
+    fn parse_export_section(
+        &mut self,
+        exports: &mut crate::ExportSection,
+        section: wasmparser::ExportSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_export_section(self, exports, section)
+    }
+
+    /// Parses the single [`wasmparser::Export`] provided and adds it to the
+    /// `exports` section.
+    fn parse_export(&mut self, exports: &mut crate::ExportSection, export: wasmparser::Export<'_>) {
+        utils::parse_export(self, exports, export)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the functions to the `functions` section.
+    fn parse_function_section(
+        &mut self,
+        functions: &mut crate::FunctionSection,
+        section: wasmparser::FunctionSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_function_section(self, functions, section)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the globals to the `globals` section.
+    fn parse_global_section(
+        &mut self,
+        globals: &mut crate::GlobalSection,
+        section: wasmparser::GlobalSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_global_section(self, globals, section)
+    }
+
+    /// Parses the single [`wasmparser::Global`] provided and adds it to the
+    /// `globals` section.
+    fn parse_global(
+        &mut self,
+        globals: &mut crate::GlobalSection,
+        global: wasmparser::Global<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_global(self, globals, global)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the imports to the `import` section.
+    fn parse_import_section(
+        &mut self,
+        imports: &mut crate::ImportSection,
+        section: wasmparser::ImportSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_import_section(self, imports, section)
+    }
+
+    /// Parses the single [`wasmparser::Import`] provided and adds it to the
+    /// `import` section.
+    fn parse_import(
+        &mut self,
+        imports: &mut crate::ImportSection,
+        import: wasmparser::Import<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_import(self, imports, import)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the memories to the `memories` section.
+    fn parse_memory_section(
+        &mut self,
+        memories: &mut crate::MemorySection,
+        section: wasmparser::MemorySectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_memory_section(self, memories, section)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the tables to the `tables` section.
+    fn parse_table_section(
+        &mut self,
+        tables: &mut crate::TableSection,
+        section: wasmparser::TableSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_table_section(self, tables, section)
+    }
+
+    /// Parses a single [`wasmparser::Table`] and adds it to the `tables` section.
+    fn parse_table(
+        &mut self,
+        tables: &mut crate::TableSection,
+        table: wasmparser::Table<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_table(self, tables, table)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the tags to the `tags` section.
+    fn parse_tag_section(
+        &mut self,
+        tags: &mut crate::TagSection,
+        section: wasmparser::TagSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_tag_section(self, tags, section)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the types to the `types` section.
+    fn parse_type_section(
+        &mut self,
+        types: &mut crate::TypeSection,
+        section: wasmparser::TypeSectionReader<'_>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_type_section(self, types, section)
+    }
+
+    /// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section.
+    fn parse_recursive_type_group(
+        &mut self,
+        types: &mut crate::TypeSection,
+        rec_group: wasmparser::RecGroup,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_recursive_type_group(self, types, rec_group)
+    }
+
+    fn parse_unknown_section(
+        &mut self,
+        module: &mut crate::Module,
+        id: u8,
+        contents: &[u8],
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_unknown_section(self, module, id, contents)
+    }
+
+    /// A hook method that is called inside [`Reencode::parse_core_module`]
+    /// before and after every non-custom core wasm section.
+    ///
+    /// This method can be used to insert new custom sections in between those
+    /// sections, or to detect when a non-custom section is missing and insert
+    /// it in the [proper order].
+    ///
+    /// The `after` parameter is `None` iff the hook is called before the first
+    /// non-custom section, and `Some(s)` afterwards, where `s` is the
+    /// [`SectionId`] of the previous non-custom section.
+    ///
+    /// The `before` parameter is `None` iff the hook is called after the last
+    /// non-custom section, and `Some(s)` beforehand, where `s` is the
+    /// [`SectionId`] of the following non-custom section.
+    ///
+    /// [proper order]: https://webassembly.github.io/spec/core/binary/modules.html#binary-module
+    /// [`SectionId`]: crate::SectionId
+    fn intersperse_section_hook(
+        &mut self,
+        module: &mut crate::Module,
+        after: Option<crate::SectionId>,
+        before: Option<crate::SectionId>,
+    ) -> Result<(), Error<Self::Error>> {
+        utils::intersperse_section_hook(self, module, after, before)
+    }
+
+    fn parse_core_module(
+        &mut self,
+        module: &mut crate::Module,
+        parser: wasmparser::Parser,
+        data: &[u8],
+    ) -> Result<(), Error<Self::Error>> {
+        utils::parse_core_module(self, module, parser, data)
+    }
+}
+
+/// An error when re-encoding from `wasmparser` to `wasm-encoder`.
+#[derive(Debug)]
+pub enum Error<E = Infallible> {
+    /// There was a type reference that was canonicalized and no longer
+    /// references an index into a module's types space, so we cannot encode it
+    /// into a Wasm binary again.
+    CanonicalizedHeapTypeReference,
+    /// The const expression is invalid: not actually constant or something like
+    /// that.
+    InvalidConstExpr,
+    /// There was a section that does not belong into a core wasm module.
+    UnexpectedNonCoreModuleSection,
+    /// There was an error when parsing.
+    ParseError(wasmparser::BinaryReaderError),
+    /// There was a user-defined error when re-encoding.
+    UserError(E),
+}
+
+impl<E> From<wasmparser::BinaryReaderError> for Error<E> {
+    fn from(err: wasmparser::BinaryReaderError) -> Self {
+        Self::ParseError(err)
+    }
+}
+
+impl<E: std::fmt::Display> std::fmt::Display for Error<E> {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+        match self {
+            Self::ParseError(_e) => {
+                write!(fmt, "There was an error when parsing")
+            }
+            Self::UserError(e) => write!(fmt, "{e}"),
+            Self::InvalidConstExpr => write!(fmt, "The const expression was invalid"),
+            Self::UnexpectedNonCoreModuleSection => write!(
+                fmt,
+                "There was a section that does not belong into a core wasm module"
+            ),
+            Self::CanonicalizedHeapTypeReference => write!(
+                fmt,
+                "There was a canonicalized heap type reference without type index information"
+            ),
+        }
+    }
+}
+
+impl<E: 'static + std::error::Error> std::error::Error for Error<E> {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            Self::ParseError(e) => Some(e),
+            Self::UserError(e) => Some(e),
+            Self::InvalidConstExpr
+            | Self::CanonicalizedHeapTypeReference
+            | Self::UnexpectedNonCoreModuleSection => None,
+        }
+    }
+}
+
+/// Reencodes `wasmparser` into `wasm-encoder` so that the encoded wasm is
+/// identical to the input and can be parsed and encoded again.
+#[derive(Debug)]
+pub struct RoundtripReencoder;
+
+impl Reencode for RoundtripReencoder {
+    type Error = Infallible;
+}
+
+#[allow(missing_docs)] // FIXME
+pub mod utils {
+    use super::{Error, Reencode};
+
+    pub fn parse_core_module<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        module: &mut crate::Module,
+        parser: wasmparser::Parser,
+        data: &[u8],
+    ) -> Result<(), Error<T::Error>> {
+        fn handle_intersperse_section_hook<T: ?Sized + Reencode>(
+            reencoder: &mut T,
+            module: &mut crate::Module,
+            last_section: &mut Option<crate::SectionId>,
+            next_section: Option<crate::SectionId>,
+        ) -> Result<(), Error<T::Error>> {
+            let after = std::mem::replace(last_section, next_section.clone());
+            let before = next_section;
+            reencoder.intersperse_section_hook(module, after, before)
+        }
+
+        let mut sections = parser.parse_all(data);
+        let mut next_section = sections.next();
+        let mut last_section = None;
+
+        'outer: while let Some(section) = next_section {
+            match section? {
+                wasmparser::Payload::Version {
+                    encoding: wasmparser::Encoding::Module,
+                    ..
+                } => (),
+                wasmparser::Payload::Version { .. } => {
+                    return Err(Error::UnexpectedNonCoreModuleSection)
+                }
+                wasmparser::Payload::TypeSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Type),
+                    )?;
+                    let mut types = crate::TypeSection::new();
+                    reencoder.parse_type_section(&mut types, section)?;
+                    module.section(&types);
+                }
+                wasmparser::Payload::ImportSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Import),
+                    )?;
+                    let mut imports = crate::ImportSection::new();
+                    reencoder.parse_import_section(&mut imports, section)?;
+                    module.section(&imports);
+                }
+                wasmparser::Payload::FunctionSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Function),
+                    )?;
+                    let mut functions = crate::FunctionSection::new();
+                    reencoder.parse_function_section(&mut functions, section)?;
+                    module.section(&functions);
+                }
+                wasmparser::Payload::TableSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Table),
+                    )?;
+                    let mut tables = crate::TableSection::new();
+                    reencoder.parse_table_section(&mut tables, section)?;
+                    module.section(&tables);
+                }
+                wasmparser::Payload::MemorySection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Memory),
+                    )?;
+                    let mut memories = crate::MemorySection::new();
+                    reencoder.parse_memory_section(&mut memories, section)?;
+                    module.section(&memories);
+                }
+                wasmparser::Payload::TagSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Tag),
+                    )?;
+                    let mut tags = crate::TagSection::new();
+                    reencoder.parse_tag_section(&mut tags, section)?;
+                    module.section(&tags);
+                }
+                wasmparser::Payload::GlobalSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Global),
+                    )?;
+                    let mut globals = crate::GlobalSection::new();
+                    reencoder.parse_global_section(&mut globals, section)?;
+                    module.section(&globals);
+                }
+                wasmparser::Payload::ExportSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Export),
+                    )?;
+                    let mut exports = crate::ExportSection::new();
+                    reencoder.parse_export_section(&mut exports, section)?;
+                    module.section(&exports);
+                }
+                wasmparser::Payload::StartSection { func, .. } => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Start),
+                    )?;
+                    module.section(&crate::StartSection {
+                        function_index: reencoder.function_index(func),
+                    });
+                }
+                wasmparser::Payload::ElementSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Element),
+                    )?;
+                    let mut elements = crate::ElementSection::new();
+                    reencoder.parse_element_section(&mut elements, section)?;
+                    module.section(&elements);
+                }
+                wasmparser::Payload::DataCountSection { count, .. } => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::DataCount),
+                    )?;
+                    module.section(&crate::DataCountSection { count });
+                }
+                wasmparser::Payload::DataSection(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Data),
+                    )?;
+                    let mut data = crate::DataSection::new();
+                    reencoder.parse_data_section(&mut data, section)?;
+                    module.section(&data);
+                }
+                wasmparser::Payload::CodeSectionStart { count, .. } => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Code),
+                    )?;
+                    let mut codes = crate::CodeSection::new();
+                    for _ in 0..count {
+                        if let Some(Ok(wasmparser::Payload::CodeSectionEntry(section))) =
+                            sections.next()
+                        {
+                            reencoder.parse_function_body(&mut codes, section)?;
+                        } else {
+                            return Err(Error::UnexpectedNonCoreModuleSection);
+                        }
+                    }
+                    module.section(&codes);
+                }
+                wasmparser::Payload::CodeSectionEntry(section) => {
+                    handle_intersperse_section_hook(
+                        reencoder,
+                        module,
+                        &mut last_section,
+                        Some(crate::SectionId::Code),
+                    )?;
+                    // we can't do better than start a new code section here
+                    let mut codes = crate::CodeSection::new();
+                    reencoder.parse_function_body(&mut codes, section)?;
+                    while let Some(section) = sections.next() {
+                        let section = section?;
+                        if let wasmparser::Payload::CodeSectionEntry(section) = section {
+                            reencoder.parse_function_body(&mut codes, section)?;
+                        } else {
+                            module.section(&codes);
+                            next_section = Some(Ok(section));
+                            continue 'outer;
+                        }
+                    }
+                    module.section(&codes);
+                }
+                wasmparser::Payload::ModuleSection { .. }
+                | wasmparser::Payload::InstanceSection(_)
+                | wasmparser::Payload::CoreTypeSection(_)
+                | wasmparser::Payload::ComponentSection { .. }
+                | wasmparser::Payload::ComponentInstanceSection(_)
+                | wasmparser::Payload::ComponentAliasSection(_)
+                | wasmparser::Payload::ComponentTypeSection(_)
+                | wasmparser::Payload::ComponentCanonicalSection(_)
+                | wasmparser::Payload::ComponentStartSection { .. }
+                | wasmparser::Payload::ComponentImportSection(_)
+                | wasmparser::Payload::ComponentExportSection(_) => {
+                    return Err(Error::UnexpectedNonCoreModuleSection)
+                }
+                wasmparser::Payload::CustomSection(section) => {
+                    reencoder.parse_custom_section(module, section)?;
+                }
+                wasmparser::Payload::UnknownSection { id, contents, .. } => {
+                    reencoder.parse_unknown_section(module, id, contents)?;
+                }
+                wasmparser::Payload::End(_) => {
+                    handle_intersperse_section_hook(reencoder, module, &mut last_section, None)?;
+                }
+            }
+
+            next_section = sections.next();
+        }
+
+        Ok(())
+    }
+
+    /// A hook method that is called inside [`Reencode::parse_core_module`]
+    /// before and after every non-custom core wasm section.
+    ///
+    /// This method can be used to insert new custom sections in between those
+    /// sections, or to detect when a non-custom section is missing and insert
+    /// it in the [proper order].
+    ///
+    /// The `after` parameter is `None` iff the hook is called before the first
+    /// non-custom section, and `Some(s)` afterwards, where `s` is the
+    /// [`SectionId`] of the previous non-custom section.
+    ///
+    /// The `before` parameter is `None` iff the hook is called after the last
+    /// non-custom section, and `Some(s)` beforehand, where `s` is the
+    /// [`SectionId`] of the following non-custom section.
+    ///
+    /// [proper order]: https://webassembly.github.io/spec/core/binary/modules.html#binary-module
+    /// [`SectionId`]: crate::SectionId
+    pub fn intersperse_section_hook<T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        _module: &mut crate::Module,
+        _after: Option<crate::SectionId>,
+        _before: Option<crate::SectionId>,
+    ) -> Result<(), Error<T::Error>> {
+        Ok(())
+    }
+
+    pub fn component_primitive_val_type<T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        ty: wasmparser::PrimitiveValType,
+    ) -> crate::component::PrimitiveValType {
+        match ty {
+            wasmparser::PrimitiveValType::Bool => crate::component::PrimitiveValType::Bool,
+            wasmparser::PrimitiveValType::S8 => crate::component::PrimitiveValType::S8,
+            wasmparser::PrimitiveValType::U8 => crate::component::PrimitiveValType::U8,
+            wasmparser::PrimitiveValType::S16 => crate::component::PrimitiveValType::S16,
+            wasmparser::PrimitiveValType::U16 => crate::component::PrimitiveValType::U16,
+            wasmparser::PrimitiveValType::S32 => crate::component::PrimitiveValType::S32,
+            wasmparser::PrimitiveValType::U32 => crate::component::PrimitiveValType::U32,
+            wasmparser::PrimitiveValType::S64 => crate::component::PrimitiveValType::S64,
+            wasmparser::PrimitiveValType::U64 => crate::component::PrimitiveValType::U64,
+            wasmparser::PrimitiveValType::F32 => crate::component::PrimitiveValType::F32,
+            wasmparser::PrimitiveValType::F64 => crate::component::PrimitiveValType::F64,
+            wasmparser::PrimitiveValType::Char => crate::component::PrimitiveValType::Char,
+            wasmparser::PrimitiveValType::String => crate::component::PrimitiveValType::String,
+        }
+    }
+
+    pub fn memory_index<T: ?Sized + Reencode>(_reencoder: &mut T, memory: u32) -> u32 {
+        memory
+    }
+
+    pub fn mem_arg<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        arg: wasmparser::MemArg,
+    ) -> crate::MemArg {
+        crate::MemArg {
+            offset: arg.offset,
+            align: arg.align.into(),
+            memory_index: reencoder.memory_index(arg.memory),
+        }
+    }
+
+    pub fn ordering<T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        arg: wasmparser::Ordering,
+    ) -> crate::Ordering {
+        match arg {
+            wasmparser::Ordering::SeqCst => crate::Ordering::SeqCst,
+            wasmparser::Ordering::AcqRel => crate::Ordering::AcqRel,
+        }
+    }
+
+    pub fn function_index<T: ?Sized + Reencode>(_reencoder: &mut T, func: u32) -> u32 {
+        func
+    }
+
+    pub fn tag_index<T: ?Sized + Reencode>(_reencoder: &mut T, tag: u32) -> u32 {
+        tag
+    }
+
+    pub fn catch<T: ?Sized + Reencode>(reencoder: &mut T, arg: wasmparser::Catch) -> crate::Catch {
+        match arg {
+            wasmparser::Catch::One { tag, label } => crate::Catch::One {
+                tag: reencoder.tag_index(tag),
+                label,
+            },
+            wasmparser::Catch::OneRef { tag, label } => crate::Catch::OneRef {
+                tag: reencoder.tag_index(tag),
+                label,
+            },
+            wasmparser::Catch::All { label } => crate::Catch::All { label },
+            wasmparser::Catch::AllRef { label } => crate::Catch::AllRef { label },
+        }
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and
+    /// adds the custom section to the `module`.
+    pub fn parse_custom_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        module: &mut crate::Module,
+        section: wasmparser::CustomSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        module.section(&reencoder.custom_section(section));
+        Ok(())
+    }
+
+    /// Converts the input `section` given from the `wasmparser` crate into an
+    /// encoded custom section.
+    pub fn custom_section<'a, T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        section: wasmparser::CustomSectionReader<'a>,
+    ) -> crate::CustomSection<'a> {
+        crate::CustomSection {
+            data: section.data().into(),
+            name: section.name().into(),
+        }
+    }
+
+    pub fn export_kind<T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        external_kind: wasmparser::ExternalKind,
+    ) -> crate::ExportKind {
+        match external_kind {
+            wasmparser::ExternalKind::Func => crate::ExportKind::Func,
+            wasmparser::ExternalKind::Table => crate::ExportKind::Table,
+            wasmparser::ExternalKind::Memory => crate::ExportKind::Memory,
+            wasmparser::ExternalKind::Global => crate::ExportKind::Global,
+            wasmparser::ExternalKind::Tag => crate::ExportKind::Tag,
+        }
+    }
+
+    pub fn memory_type<T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        memory_ty: wasmparser::MemoryType,
+    ) -> crate::MemoryType {
+        crate::MemoryType {
+            minimum: memory_ty.initial,
+            maximum: memory_ty.maximum,
+            memory64: memory_ty.memory64,
+            shared: memory_ty.shared,
+            page_size_log2: memory_ty.page_size_log2,
+        }
+    }
+
+    pub fn tag_kind<T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        kind: wasmparser::TagKind,
+    ) -> crate::TagKind {
+        match kind {
+            wasmparser::TagKind::Exception => crate::TagKind::Exception,
+        }
+    }
+
+    pub fn type_index<T: ?Sized + Reencode>(_reencoder: &mut T, ty: u32) -> u32 {
+        ty
+    }
+
+    pub fn tag_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        tag_ty: wasmparser::TagType,
+    ) -> crate::TagType {
+        crate::TagType {
+            kind: reencoder.tag_kind(tag_ty.kind),
+            func_type_idx: reencoder.type_index(tag_ty.func_type_idx),
+        }
+    }
+
+    pub fn abstract_heap_type<T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        value: wasmparser::AbstractHeapType,
+    ) -> crate::AbstractHeapType {
+        use wasmparser::AbstractHeapType::*;
+        match value {
+            Func => crate::AbstractHeapType::Func,
+            Extern => crate::AbstractHeapType::Extern,
+            Any => crate::AbstractHeapType::Any,
+            None => crate::AbstractHeapType::None,
+            NoExtern => crate::AbstractHeapType::NoExtern,
+            NoFunc => crate::AbstractHeapType::NoFunc,
+            Eq => crate::AbstractHeapType::Eq,
+            Struct => crate::AbstractHeapType::Struct,
+            Array => crate::AbstractHeapType::Array,
+            I31 => crate::AbstractHeapType::I31,
+            Exn => crate::AbstractHeapType::Exn,
+            NoExn => crate::AbstractHeapType::NoExn,
+        }
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the types to the `types` section.
+    pub fn parse_type_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        types: &mut crate::TypeSection,
+        section: wasmparser::TypeSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for rec_group in section {
+            reencoder.parse_recursive_type_group(types, rec_group?)?;
+        }
+        Ok(())
+    }
+
+    /// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section.
+    pub fn parse_recursive_type_group<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        types: &mut crate::TypeSection,
+        rec_group: wasmparser::RecGroup,
+    ) -> Result<(), Error<T::Error>> {
+        if rec_group.is_explicit_rec_group() {
+            let subtypes = rec_group
+                .into_types()
+                .map(|t| reencoder.sub_type(t))
+                .collect::<Result<Vec<_>, _>>()?;
+            types.rec(subtypes);
+        } else {
+            let ty = rec_group.into_types().next().unwrap();
+            types.subtype(&reencoder.sub_type(ty)?);
+        }
+        Ok(())
+    }
+
+    pub fn sub_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        sub_ty: wasmparser::SubType,
+    ) -> Result<crate::SubType, Error<T::Error>> {
+        Ok(crate::SubType {
+            is_final: sub_ty.is_final,
+            supertype_idx: sub_ty
+                .supertype_idx
+                .map(|i| {
+                    i.as_module_index()
+                        .map(|ty| reencoder.type_index(ty))
+                        .ok_or(Error::CanonicalizedHeapTypeReference)
+                })
+                .transpose()?,
+            composite_type: reencoder.composite_type(sub_ty.composite_type)?,
+        })
+    }
+
+    pub fn composite_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        composite_ty: wasmparser::CompositeType,
+    ) -> Result<crate::CompositeType, Error<T::Error>> {
+        Ok(match composite_ty {
+            wasmparser::CompositeType::Func(f) => {
+                crate::CompositeType::Func(reencoder.func_type(f)?)
+            }
+            wasmparser::CompositeType::Array(a) => {
+                crate::CompositeType::Array(reencoder.array_type(a)?)
+            }
+            wasmparser::CompositeType::Struct(s) => {
+                crate::CompositeType::Struct(reencoder.struct_type(s)?)
+            }
+        })
+    }
+
+    pub fn func_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        func_ty: wasmparser::FuncType,
+    ) -> Result<crate::FuncType, Error<T::Error>> {
+        let mut buf = Vec::with_capacity(func_ty.params().len() + func_ty.results().len());
+        for ty in func_ty.params().iter().chain(func_ty.results()).copied() {
+            buf.push(reencoder.val_type(ty)?);
+        }
+        Ok(crate::FuncType::from_parts(
+            buf.into(),
+            func_ty.params().len(),
+        ))
+    }
+
+    pub fn array_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        array_ty: wasmparser::ArrayType,
+    ) -> Result<crate::ArrayType, Error<T::Error>> {
+        Ok(crate::ArrayType(reencoder.field_type(array_ty.0)?))
+    }
+
+    pub fn struct_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        struct_ty: wasmparser::StructType,
+    ) -> Result<crate::StructType, Error<T::Error>> {
+        Ok(crate::StructType {
+            fields: struct_ty
+                .fields
+                .iter()
+                .map(|field_ty| reencoder.field_type(field_ty.clone()))
+                .collect::<Result<_, _>>()?,
+        })
+    }
+
+    pub fn field_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        field_ty: wasmparser::FieldType,
+    ) -> Result<crate::FieldType, Error<T::Error>> {
+        Ok(crate::FieldType {
+            element_type: reencoder.storage_type(field_ty.element_type)?,
+            mutable: field_ty.mutable,
+        })
+    }
+
+    pub fn storage_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        storage_ty: wasmparser::StorageType,
+    ) -> Result<crate::StorageType, Error<T::Error>> {
+        Ok(match storage_ty {
+            wasmparser::StorageType::I8 => crate::StorageType::I8,
+            wasmparser::StorageType::I16 => crate::StorageType::I16,
+            wasmparser::StorageType::Val(v) => crate::StorageType::Val(reencoder.val_type(v)?),
+        })
+    }
+
+    pub fn val_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        val_ty: wasmparser::ValType,
+    ) -> Result<crate::ValType, Error<T::Error>> {
+        Ok(match val_ty {
+            wasmparser::ValType::I32 => crate::ValType::I32,
+            wasmparser::ValType::I64 => crate::ValType::I64,
+            wasmparser::ValType::F32 => crate::ValType::F32,
+            wasmparser::ValType::F64 => crate::ValType::F64,
+            wasmparser::ValType::V128 => crate::ValType::V128,
+            wasmparser::ValType::Ref(r) => crate::ValType::Ref(reencoder.ref_type(r)?),
+        })
+    }
+
+    pub fn ref_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        ref_type: wasmparser::RefType,
+    ) -> Result<crate::RefType, Error<T::Error>> {
+        Ok(crate::RefType {
+            nullable: ref_type.is_nullable(),
+            heap_type: reencoder.heap_type(ref_type.heap_type())?,
+        })
+    }
+
+    pub fn heap_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        heap_type: wasmparser::HeapType,
+    ) -> Result<crate::HeapType, Error<T::Error>> {
+        Ok(match heap_type {
+            wasmparser::HeapType::Concrete(i) => crate::HeapType::Concrete(
+                i.as_module_index()
+                    .map(|ty| reencoder.type_index(ty))
+                    .ok_or(Error::CanonicalizedHeapTypeReference)?,
+            ),
+            wasmparser::HeapType::Abstract { shared, ty } => crate::HeapType::Abstract {
+                shared,
+                ty: reencoder.abstract_heap_type(ty),
+            },
+        })
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the tables to the `tables` section.
+    pub fn parse_table_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        tables: &mut crate::TableSection,
+        section: wasmparser::TableSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for table in section {
+            reencoder.parse_table(tables, table?)?;
+        }
+        Ok(())
+    }
+
+    /// Parses a single [`wasmparser::Table`] and adds it to the `tables` section.
+    pub fn parse_table<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        tables: &mut crate::TableSection,
+        table: wasmparser::Table<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        let ty = reencoder.table_type(table.ty)?;
+        match table.init {
+            wasmparser::TableInit::RefNull => {
+                tables.table(ty);
+            }
+            wasmparser::TableInit::Expr(e) => {
+                tables.table_with_init(ty, &reencoder.const_expr(e)?);
+            }
+        }
+        Ok(())
+    }
+
+    pub fn table_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        table_ty: wasmparser::TableType,
+    ) -> Result<crate::TableType, Error<T::Error>> {
+        Ok(crate::TableType {
+            element_type: reencoder.ref_type(table_ty.element_type)?,
+            minimum: table_ty.initial,
+            maximum: table_ty.maximum,
+            table64: table_ty.table64,
+        })
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the tags to the `tags` section.
+    pub fn parse_tag_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        tags: &mut crate::TagSection,
+        section: wasmparser::TagSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for tag in section {
+            let tag = tag?;
+            tags.tag(reencoder.tag_type(tag));
+        }
+        Ok(())
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the exports to the `exports` section.
+    pub fn parse_export_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        exports: &mut crate::ExportSection,
+        section: wasmparser::ExportSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for export in section {
+            reencoder.parse_export(exports, export?);
+        }
+        Ok(())
+    }
+
+    /// Parses the single [`wasmparser::Export`] provided and adds it to the
+    /// `exports` section.
+    pub fn parse_export<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        exports: &mut crate::ExportSection,
+        export: wasmparser::Export<'_>,
+    ) {
+        exports.export(
+            export.name,
+            reencoder.export_kind(export.kind),
+            match export.kind {
+                wasmparser::ExternalKind::Func => reencoder.function_index(export.index),
+                wasmparser::ExternalKind::Table => reencoder.table_index(export.index),
+                wasmparser::ExternalKind::Memory => reencoder.memory_index(export.index),
+                wasmparser::ExternalKind::Global => reencoder.global_index(export.index),
+                wasmparser::ExternalKind::Tag => reencoder.tag_index(export.index),
+            },
+        );
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the globals to the `globals` section.
+    pub fn parse_global_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        globals: &mut crate::GlobalSection,
+        section: wasmparser::GlobalSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for global in section {
+            reencoder.parse_global(globals, global?)?;
+        }
+        Ok(())
+    }
+
+    /// Parses the single [`wasmparser::Global`] provided and adds it to the
+    /// `globals` section.
+    pub fn parse_global<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        globals: &mut crate::GlobalSection,
+        global: wasmparser::Global<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        globals.global(
+            reencoder.global_type(global.ty)?,
+            &reencoder.const_expr(global.init_expr)?,
+        );
+        Ok(())
+    }
+
+    pub fn global_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        global_ty: wasmparser::GlobalType,
+    ) -> Result<crate::GlobalType, Error<T::Error>> {
+        Ok(crate::GlobalType {
+            val_type: reencoder.val_type(global_ty.content_type)?,
+            mutable: global_ty.mutable,
+            shared: global_ty.shared,
+        })
+    }
+
+    pub fn entity_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        type_ref: wasmparser::TypeRef,
+    ) -> Result<crate::EntityType, Error<T::Error>> {
+        Ok(match type_ref {
+            wasmparser::TypeRef::Func(i) => crate::EntityType::Function(reencoder.type_index(i)),
+            wasmparser::TypeRef::Table(t) => crate::EntityType::Table(reencoder.table_type(t)?),
+            wasmparser::TypeRef::Memory(m) => crate::EntityType::Memory(reencoder.memory_type(m)),
+            wasmparser::TypeRef::Global(g) => crate::EntityType::Global(reencoder.global_type(g)?),
+            wasmparser::TypeRef::Tag(t) => crate::EntityType::Tag(reencoder.tag_type(t)),
+        })
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the imports to the `import` section.
+    pub fn parse_import_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        imports: &mut crate::ImportSection,
+        section: wasmparser::ImportSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for import in section {
+            reencoder.parse_import(imports, import?)?;
+        }
+        Ok(())
+    }
+
+    /// Parses the single [`wasmparser::Import`] provided and adds it to the
+    /// `import` section.
+    pub fn parse_import<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        imports: &mut crate::ImportSection,
+        import: wasmparser::Import<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        imports.import(
+            import.module,
+            import.name,
+            reencoder.entity_type(import.ty)?,
+        );
+        Ok(())
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the memories to the `memories` section.
+    pub fn parse_memory_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        memories: &mut crate::MemorySection,
+        section: wasmparser::MemorySectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for memory in section {
+            let memory = memory?;
+            memories.memory(reencoder.memory_type(memory));
+        }
+        Ok(())
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the functions to the `functions` section.
+    pub fn parse_function_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        functions: &mut crate::FunctionSection,
+        section: wasmparser::FunctionSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for func in section {
+            functions.function(reencoder.type_index(func?));
+        }
+        Ok(())
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the data to the `data` section.
+    pub fn parse_data_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        data: &mut crate::DataSection,
+        section: wasmparser::DataSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for datum in section {
+            reencoder.parse_data(data, datum?)?;
+        }
+        Ok(())
+    }
+
+    /// Parses a single [`wasmparser::Data`] and adds it to the `data` section.
+    pub fn parse_data<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        data: &mut crate::DataSection,
+        datum: wasmparser::Data<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        match datum.kind {
+            wasmparser::DataKind::Active {
+                memory_index,
+                offset_expr,
+            } => data.active(
+                reencoder.memory_index(memory_index),
+                &reencoder.const_expr(offset_expr)?,
+                datum.data.iter().copied(),
+            ),
+            wasmparser::DataKind::Passive => data.passive(datum.data.iter().copied()),
+        };
+        Ok(())
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the elements to the `element` section.
+    pub fn parse_element_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        elements: &mut crate::ElementSection,
+        section: wasmparser::ElementSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for element in section {
+            reencoder.parse_element(elements, element?)?;
+        }
+        Ok(())
+    }
+
+    /// Parses the single [`wasmparser::Element`] provided and adds it to the
+    /// `element` section.
+    pub fn parse_element<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        elements: &mut crate::ElementSection,
+        element: wasmparser::Element<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        let mut funcs;
+        let mut exprs;
+        let elems = match element.items {
+            wasmparser::ElementItems::Functions(f) => {
+                funcs = Vec::new();
+                for func in f {
+                    funcs.push(reencoder.function_index(func?));
+                }
+                crate::Elements::Functions(&funcs)
+            }
+            wasmparser::ElementItems::Expressions(ty, e) => {
+                exprs = Vec::new();
+                for expr in e {
+                    exprs.push(reencoder.const_expr(expr?)?);
+                }
+                crate::Elements::Expressions(reencoder.ref_type(ty)?, &exprs)
+            }
+        };
+        match element.kind {
+            wasmparser::ElementKind::Active {
+                table_index,
+                offset_expr,
+            } => elements.active(
+                table_index.map(|t| reencoder.table_index(t)),
+                &reencoder.const_expr(offset_expr)?,
+                elems,
+            ),
+            wasmparser::ElementKind::Passive => elements.passive(elems),
+            wasmparser::ElementKind::Declared => elements.declared(elems),
+        };
+        Ok(())
+    }
+
+    pub fn table_index<T: ?Sized + Reencode>(_reencoder: &mut T, table: u32) -> u32 {
+        table
+    }
+
+    pub fn global_index<T: ?Sized + Reencode>(_reencoder: &mut T, global: u32) -> u32 {
+        global
+    }
+
+    pub fn data_index<T: ?Sized + Reencode>(_reencoder: &mut T, data: u32) -> u32 {
+        data
+    }
+
+    pub fn element_index<T: ?Sized + Reencode>(_reencoder: &mut T, element: u32) -> u32 {
+        element
+    }
+
+    pub fn const_expr<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        const_expr: wasmparser::ConstExpr,
+    ) -> Result<crate::ConstExpr, Error<T::Error>> {
+        let mut ops = const_expr.get_operators_reader().into_iter();
+
+        let result = match ops.next() {
+            Some(Ok(wasmparser::Operator::I32Const { value })) => {
+                crate::ConstExpr::i32_const(value)
+            }
+            Some(Ok(wasmparser::Operator::I64Const { value })) => {
+                crate::ConstExpr::i64_const(value)
+            }
+            Some(Ok(wasmparser::Operator::F32Const { value })) => {
+                crate::ConstExpr::f32_const(f32::from_bits(value.bits()))
+            }
+            Some(Ok(wasmparser::Operator::F64Const { value })) => {
+                crate::ConstExpr::f64_const(f64::from_bits(value.bits()))
+            }
+            Some(Ok(wasmparser::Operator::V128Const { value })) => {
+                crate::ConstExpr::v128_const(i128::from_le_bytes(*value.bytes()))
+            }
+            Some(Ok(wasmparser::Operator::RefNull { hty })) => {
+                crate::ConstExpr::ref_null(reencoder.heap_type(hty)?)
+            }
+            Some(Ok(wasmparser::Operator::RefFunc { function_index })) => {
+                crate::ConstExpr::ref_func(reencoder.function_index(function_index))
+            }
+            Some(Ok(wasmparser::Operator::GlobalGet { global_index })) => {
+                crate::ConstExpr::global_get(reencoder.global_index(global_index))
+            }
+
+            // TODO: support the extended-const proposal.
+            Some(Ok(_op)) => return Err(Error::InvalidConstExpr),
+
+            Some(Err(e)) => return Err(Error::ParseError(e)),
+            None => return Err(Error::InvalidConstExpr),
+        };
+
+        match (ops.next(), ops.next()) {
+            (Some(Ok(wasmparser::Operator::End)), None) => Ok(result),
+            _ => Err(Error::InvalidConstExpr),
+        }
+    }
+
+    pub fn block_type<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        arg: wasmparser::BlockType,
+    ) -> Result<crate::BlockType, Error<T::Error>> {
+        match arg {
+            wasmparser::BlockType::Empty => Ok(crate::BlockType::Empty),
+            wasmparser::BlockType::FuncType(n) => {
+                Ok(crate::BlockType::FunctionType(reencoder.type_index(n)))
+            }
+            wasmparser::BlockType::Type(t) => Ok(crate::BlockType::Result(reencoder.val_type(t)?)),
+        }
+    }
+
+    pub fn instruction<'a, T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        arg: wasmparser::Operator<'a>,
+    ) -> Result<crate::Instruction<'a>, Error<T::Error>> {
+        use crate::Instruction;
+
+        macro_rules! translate {
+            ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
+                Ok(match arg {
+                    $(
+                        wasmparser::Operator::$op $({ $($arg),* })? => {
+                            $(
+                                $(let $arg = translate!(map $arg $arg);)*
+                            )?
+                            translate!(build $op $($($arg)*)?)
+                        }
+                    )*
+                })
+            };
+
+            // This case is used to map, based on the name of the field, from the
+            // wasmparser payload type to the wasm-encoder payload type through
+            // `Translator` as applicable.
+            (map $arg:ident tag_index) => (reencoder.tag_index($arg));
+            (map $arg:ident function_index) => (reencoder.function_index($arg));
+            (map $arg:ident table) => (reencoder.table_index($arg));
+            (map $arg:ident table_index) => (reencoder.table_index($arg));
+            (map $arg:ident dst_table) => (reencoder.table_index($arg));
+            (map $arg:ident src_table) => (reencoder.table_index($arg));
+            (map $arg:ident type_index) => (reencoder.type_index($arg));
+            (map $arg:ident array_type_index) => (reencoder.type_index($arg));
+            (map $arg:ident array_type_index_dst) => (reencoder.type_index($arg));
+            (map $arg:ident array_type_index_src) => (reencoder.type_index($arg));
+            (map $arg:ident struct_type_index) => (reencoder.type_index($arg));
+            (map $arg:ident global_index) => (reencoder.global_index($arg));
+            (map $arg:ident mem) => (reencoder.memory_index($arg));
+            (map $arg:ident src_mem) => (reencoder.memory_index($arg));
+            (map $arg:ident dst_mem) => (reencoder.memory_index($arg));
+            (map $arg:ident data_index) => (reencoder.data_index($arg));
+            (map $arg:ident elem_index) => (reencoder.element_index($arg));
+            (map $arg:ident array_data_index) => (reencoder.data_index($arg));
+            (map $arg:ident array_elem_index) => (reencoder.element_index($arg));
+            (map $arg:ident blockty) => (reencoder.block_type($arg)?);
+            (map $arg:ident relative_depth) => ($arg);
+            (map $arg:ident targets) => ((
+                $arg
+                    .targets()
+                    .collect::<Result<Vec<_>, wasmparser::BinaryReaderError>>()?
+                    .into(),
+                $arg.default(),
+            ));
+            (map $arg:ident ty) => (reencoder.val_type($arg)?);
+            (map $arg:ident hty) => (reencoder.heap_type($arg)?);
+            (map $arg:ident from_ref_type) => (reencoder.ref_type($arg)?);
+            (map $arg:ident to_ref_type) => (reencoder.ref_type($arg)?);
+            (map $arg:ident memarg) => (reencoder.mem_arg($arg));
+            (map $arg:ident ordering) => (reencoder.ordering($arg));
+            (map $arg:ident local_index) => ($arg);
+            (map $arg:ident value) => ($arg);
+            (map $arg:ident lane) => ($arg);
+            (map $arg:ident lanes) => ($arg);
+            (map $arg:ident array_size) => ($arg);
+            (map $arg:ident field_index) => ($arg);
+            (map $arg:ident try_table) => ($arg);
+
+            // This case takes the arguments of a wasmparser instruction and creates
+            // a wasm-encoder instruction. There are a few special cases for where
+            // the structure of a wasmparser instruction differs from that of
+            // wasm-encoder.
+            (build $op:ident) => (Instruction::$op);
+            (build BrTable $arg:ident) => (Instruction::BrTable($arg.0, $arg.1));
+            (build I32Const $arg:ident) => (Instruction::I32Const($arg));
+            (build I64Const $arg:ident) => (Instruction::I64Const($arg));
+            (build F32Const $arg:ident) => (Instruction::F32Const(f32::from_bits($arg.bits())));
+            (build F64Const $arg:ident) => (Instruction::F64Const(f64::from_bits($arg.bits())));
+            (build V128Const $arg:ident) => (Instruction::V128Const($arg.i128()));
+            (build TryTable $table:ident) => (Instruction::TryTable(reencoder.block_type($table.ty)?, {
+                $table.catches.into_iter().map(|c| reencoder.catch(c)).collect::<Vec<_>>().into()
+            }));
+            (build $op:ident $arg:ident) => (Instruction::$op($arg));
+            (build $op:ident $($arg:ident)*) => (Instruction::$op { $($arg),* });
+        }
+
+        wasmparser::for_each_operator!(translate)
+    }
+
+    /// Parses the input `section` given from the `wasmparser` crate and adds
+    /// all the code to the `code` section.
+    pub fn parse_code_section<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        code: &mut crate::CodeSection,
+        section: wasmparser::CodeSectionReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        for func in section {
+            reencoder.parse_function_body(code, func?)?;
+        }
+        Ok(())
+    }
+
+    /// Parses a single [`wasmparser::FunctionBody`] and adds it to the `code` section.
+    pub fn parse_function_body<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        code: &mut crate::CodeSection,
+        func: wasmparser::FunctionBody<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        let mut f = reencoder.new_function_with_parsed_locals(&func)?;
+        let mut reader = func.get_operators_reader()?;
+        while !reader.eof() {
+            reencoder.parse_instruction(&mut f, &mut reader)?;
+        }
+        code.function(&f);
+        Ok(())
+    }
+
+    /// Create a new [`crate::Function`] by parsing the locals declarations from the
+    /// provided [`wasmparser::FunctionBody`].
+    pub fn new_function_with_parsed_locals<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        func: &wasmparser::FunctionBody<'_>,
+    ) -> Result<crate::Function, Error<T::Error>> {
+        let mut locals = Vec::new();
+        for pair in func.get_locals_reader()? {
+            let (cnt, ty) = pair?;
+            locals.push((cnt, reencoder.val_type(ty)?));
+        }
+        Ok(crate::Function::new(locals))
+    }
+
+    /// Parses a single instruction from `reader` and adds it to `function`.
+    pub fn parse_instruction<T: ?Sized + Reencode>(
+        reencoder: &mut T,
+        function: &mut crate::Function,
+        reader: &mut wasmparser::OperatorsReader<'_>,
+    ) -> Result<(), Error<T::Error>> {
+        function.instruction(&reencoder.instruction(reader.read()?)?);
+        Ok(())
+    }
+
+    pub fn parse_unknown_section<T: ?Sized + Reencode>(
+        _reencoder: &mut T,
+        module: &mut crate::Module,
+        id: u8,
+        contents: &[u8],
+    ) -> Result<(), Error<T::Error>> {
+        module.section(&crate::RawSection { id, data: contents });
+        Ok(())
+    }
+}
+
+impl From<wasmparser::PrimitiveValType> for crate::PrimitiveValType {
+    fn from(ty: wasmparser::PrimitiveValType) -> Self {
+        RoundtripReencoder.component_primitive_val_type(ty)
+    }
+}
+
+impl From<wasmparser::MemArg> for crate::MemArg {
+    fn from(arg: wasmparser::MemArg) -> Self {
+        RoundtripReencoder.mem_arg(arg)
+    }
+}
+
+impl From<wasmparser::Ordering> for crate::Ordering {
+    fn from(arg: wasmparser::Ordering) -> Self {
+        RoundtripReencoder.ordering(arg)
+    }
+}
+
+impl TryFrom<wasmparser::BlockType> for crate::BlockType {
+    type Error = Error;
+
+    fn try_from(arg: wasmparser::BlockType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.block_type(arg)
+    }
+}
+
+impl<'a> TryFrom<wasmparser::Operator<'a>> for crate::Instruction<'a> {
+    type Error = Error;
+
+    fn try_from(arg: wasmparser::Operator<'a>) -> Result<Self, Self::Error> {
+        RoundtripReencoder.instruction(arg)
+    }
+}
+
+impl From<wasmparser::Catch> for crate::Catch {
+    fn from(arg: wasmparser::Catch) -> Self {
+        RoundtripReencoder.catch(arg)
+    }
+}
+
+impl<'a> TryFrom<wasmparser::ConstExpr<'a>> for crate::ConstExpr {
+    type Error = Error;
+
+    fn try_from(const_expr: wasmparser::ConstExpr) -> Result<Self, Self::Error> {
+        RoundtripReencoder.const_expr(const_expr)
+    }
+}
+
+impl<'a> From<wasmparser::CustomSectionReader<'a>> for crate::CustomSection<'a> {
+    fn from(section: wasmparser::CustomSectionReader<'a>) -> Self {
+        RoundtripReencoder.custom_section(section)
+    }
+}
+
+impl From<wasmparser::ExternalKind> for crate::ExportKind {
+    fn from(external_kind: wasmparser::ExternalKind) -> Self {
+        RoundtripReencoder.export_kind(external_kind)
+    }
+}
+
+impl TryFrom<wasmparser::GlobalType> for crate::GlobalType {
+    type Error = Error;
+
+    fn try_from(global_ty: wasmparser::GlobalType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.global_type(global_ty)
+    }
+}
+
+impl TryFrom<wasmparser::TypeRef> for crate::EntityType {
+    type Error = Error;
+
+    fn try_from(type_ref: wasmparser::TypeRef) -> Result<Self, Self::Error> {
+        RoundtripReencoder.entity_type(type_ref)
+    }
+}
+
+impl From<wasmparser::MemoryType> for crate::MemoryType {
+    fn from(memory_ty: wasmparser::MemoryType) -> Self {
+        RoundtripReencoder.memory_type(memory_ty)
+    }
+}
+
+impl TryFrom<wasmparser::TableType> for crate::TableType {
+    type Error = Error;
+
+    fn try_from(table_ty: wasmparser::TableType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.table_type(table_ty)
+    }
+}
+
+impl From<wasmparser::TagKind> for crate::TagKind {
+    fn from(kind: wasmparser::TagKind) -> Self {
+        RoundtripReencoder.tag_kind(kind)
+    }
+}
+
+impl From<wasmparser::TagType> for crate::TagType {
+    fn from(tag_ty: wasmparser::TagType) -> Self {
+        RoundtripReencoder.tag_type(tag_ty)
+    }
+}
+
+impl TryFrom<wasmparser::SubType> for crate::SubType {
+    type Error = Error;
+
+    fn try_from(sub_ty: wasmparser::SubType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.sub_type(sub_ty)
+    }
+}
+
+impl TryFrom<wasmparser::CompositeType> for crate::CompositeType {
+    type Error = Error;
+
+    fn try_from(composite_ty: wasmparser::CompositeType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.composite_type(composite_ty)
+    }
+}
+
+impl TryFrom<wasmparser::FuncType> for crate::FuncType {
+    type Error = Error;
+
+    fn try_from(func_ty: wasmparser::FuncType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.func_type(func_ty)
+    }
+}
+
+impl TryFrom<wasmparser::ArrayType> for crate::ArrayType {
+    type Error = Error;
+
+    fn try_from(array_ty: wasmparser::ArrayType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.array_type(array_ty)
+    }
+}
+
+impl TryFrom<wasmparser::StructType> for crate::StructType {
+    type Error = Error;
+
+    fn try_from(struct_ty: wasmparser::StructType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.struct_type(struct_ty)
+    }
+}
+
+impl TryFrom<wasmparser::FieldType> for crate::FieldType {
+    type Error = Error;
+
+    fn try_from(field_ty: wasmparser::FieldType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.field_type(field_ty)
+    }
+}
+
+impl TryFrom<wasmparser::StorageType> for crate::StorageType {
+    type Error = Error;
+
+    fn try_from(storage_ty: wasmparser::StorageType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.storage_type(storage_ty)
+    }
+}
+
+impl TryFrom<wasmparser::ValType> for crate::ValType {
+    type Error = Error;
+
+    fn try_from(val_ty: wasmparser::ValType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.val_type(val_ty)
+    }
+}
+
+impl TryFrom<wasmparser::RefType> for crate::RefType {
+    type Error = Error;
+
+    fn try_from(ref_type: wasmparser::RefType) -> Result<Self, Self::Error> {
+        RoundtripReencoder.ref_type(ref_type)
+    }
+}
+
+impl TryFrom<wasmparser::HeapType> for crate::HeapType {
+    type Error = Error;
+
+    fn try_from(heap_type: wasmparser::HeapType) -> Result<Self, Self::Error> {
+        crate::reencode::utils::heap_type(&mut crate::reencode::RoundtripReencoder, heap_type)
+    }
+}
+
+impl From<wasmparser::AbstractHeapType> for crate::AbstractHeapType {
+    fn from(value: wasmparser::AbstractHeapType) -> Self {
+        RoundtripReencoder.abstract_heap_type(value)
+    }
+}
diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs
index e73a9e9a..6478cf9c 100644
--- a/crates/wasmparser/src/features.rs
+++ b/crates/wasmparser/src/features.rs
@@ -146,6 +146,8 @@ define_wasm_features! {
         pub component_model_values: COMPONENT_MODEL_VALUES(1 << 21) = false;
         /// Support for the nested namespaces and projects in component model names.
         pub component_model_nested_names: COMPONENT_MODEL_NESTED_NAMES(1 << 22) = false;
+        /// Support for more than 32 flags per-type in the component model.
+        pub component_model_more_flags: COMPONENT_MODEL_MORE_FLAGS(1 << 23) = false;
     }
 }
 
diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs
index a0f54c8a..54bf6121 100644
--- a/crates/wasmparser/src/parser.rs
+++ b/crates/wasmparser/src/parser.rs
@@ -71,7 +71,7 @@ enum State {
 pub enum Chunk<'a> {
     /// This can be returned at any time and indicates that more data is needed
     /// to proceed with parsing. Zero bytes were consumed from the input to
-    /// [`Parser::parse`]. The `usize` value here is a hint as to how many more
+    /// [`Parser::parse`]. The `u64` value here is a hint as to how many more
     /// bytes are needed to continue parsing.
     NeedMoreData(u64),
 
diff --git a/crates/wasmparser/src/readers/core/tables.rs b/crates/wasmparser/src/readers/core/tables.rs
index e79ed33d..6c144a57 100644
--- a/crates/wasmparser/src/readers/core/tables.rs
+++ b/crates/wasmparser/src/readers/core/tables.rs
@@ -20,7 +20,7 @@ pub type TableSectionReader<'a> = SectionLimited<'a, Table<'a>>;
 
 /// Type information about a table defined in the table section of a WebAssembly
 /// module.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct Table<'a> {
     /// The type of this table, including its element type and its limits.
     pub ty: TableType,
@@ -29,7 +29,7 @@ pub struct Table<'a> {
 }
 
 /// Different modes of initializing a table.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub enum TableInit<'a> {
     /// The table is initialized to all null elements.
     RefNull,
diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs
index f39be44d..80dbd2e3 100644
--- a/crates/wasmparser/src/validator/component.rs
+++ b/crates/wasmparser/src/validator/component.rs
@@ -348,7 +348,7 @@ impl ComponentState {
 
         let id = match ty {
             crate::ComponentType::Defined(ty) => {
-                let ty = current(components).create_defined_type(ty, types, offset)?;
+                let ty = current(components).create_defined_type(ty, types, features, offset)?;
                 types.push(ty).into()
             }
             crate::ComponentType::Func(ty) => {
@@ -2512,6 +2512,7 @@ impl ComponentState {
         &self,
         ty: crate::ComponentDefinedType,
         types: &TypeList,
+        features: &WasmFeatures,
         offset: usize,
     ) -> Result<ComponentDefinedType> {
         match ty {
@@ -2529,7 +2530,7 @@ impl ComponentState {
                 self.create_tuple_type(tys.as_ref(), types, offset)
             }
             crate::ComponentDefinedType::Flags(names) => {
-                self.create_flags_type(names.as_ref(), offset)
+                self.create_flags_type(names.as_ref(), features, offset)
             }
             crate::ComponentDefinedType::Enum(cases) => {
                 self.create_enum_type(cases.as_ref(), offset)
@@ -2681,7 +2682,12 @@ impl ComponentState {
         Ok(ComponentDefinedType::Tuple(TupleType { info, types }))
     }
 
-    fn create_flags_type(&self, names: &[&str], offset: usize) -> Result<ComponentDefinedType> {
+    fn create_flags_type(
+        &self,
+        names: &[&str],
+        features: &WasmFeatures,
+        offset: usize,
+    ) -> Result<ComponentDefinedType> {
         let mut names_set = IndexSet::default();
         names_set.reserve(names.len());
 
@@ -2689,6 +2695,16 @@ impl ComponentState {
             bail!(offset, "flags must have at least one entry");
         }
 
+        if names.len() > 32 && !features.component_model_more_flags() {
+            bail!(
+                offset,
+                "cannot have more than 32 flags; this was previously \
+                 accepted and if this is required for your project please \
+                 leave a comment on \
+                 https://github.com/WebAssembly/component-model/issues/370"
+            );
+        }
+
         for name in names {
             let name = to_kebab_str(name, "flag", offset)?;
             if !names_set.insert(name.to_owned()) {
diff --git a/crates/wit-component/src/gc.rs b/crates/wit-component/src/gc.rs
index 0fa13d85..ed1bd350 100644
--- a/crates/wit-component/src/gc.rs
+++ b/crates/wit-component/src/gc.rs
@@ -4,9 +4,11 @@ use indexmap::{IndexMap, IndexSet};
 use std::{
     borrow::Cow,
     collections::{HashMap, HashSet},
+    convert::Infallible,
     mem,
     ops::Deref,
 };
+use wasm_encoder::reencode::Reencode;
 use wasm_encoder::{Encode, EntityType, Instruction, RawCustomSection};
 use wasmparser::*;
 
@@ -552,10 +554,8 @@ impl<'a> Module<'a> {
         for (i, ty) in self.live_types() {
             map.types.push(i);
 
-            types.function(
-                ty.params().iter().map(|t| map.valty(*t)),
-                ty.results().iter().map(|t| map.valty(*t)),
-            );
+            let ty = map.func_type(ty.clone())?;
+            types.func_type(&ty);
 
             // Keep track of the "empty type" to see if we can reuse an
             // existing one or one needs to be injected if a `start`
@@ -568,7 +568,7 @@ impl<'a> Module<'a> {
         let mut num_memories = 0;
         for (i, mem) in self.live_memories() {
             map.memories.push(i);
-            let ty = mem.ty.into();
+            let ty = map.memory_type(mem.ty);
             match &mem.def {
                 Definition::Import(m, n) => {
                     imports.import(m, n, ty);
@@ -582,12 +582,7 @@ impl<'a> Module<'a> {
 
         for (i, table) in self.live_tables() {
             map.tables.push(i);
-            let ty = wasm_encoder::TableType {
-                minimum: table.ty.initial,
-                maximum: table.ty.maximum,
-                element_type: map.refty(table.ty.element_type),
-                table64: table.ty.table64,
-            };
+            let ty = map.table_type(table.ty.clone())?;
             match &table.def {
                 Definition::Import(m, n) => {
                     imports.import(m, n, ty);
@@ -600,19 +595,14 @@ impl<'a> Module<'a> {
 
         for (i, global) in self.live_globals() {
             map.globals.push(i);
-            let ty = wasm_encoder::GlobalType {
-                val_type: map.valty(global.ty.content_type),
-                mutable: global.ty.mutable,
-                shared: global.ty.shared,
-            };
+            let ty = map.global_type(global.ty.clone())?;
             match &global.def {
                 Definition::Import(m, n) => {
                     imports.import(m, n, ty);
                 }
                 Definition::Local(init) => {
-                    let mut bytes = map.operators(init.get_binary_reader())?;
-                    assert_eq!(bytes.pop(), Some(0xb));
-                    globals.global(ty, &wasm_encoder::ConstExpr::raw(bytes));
+                    let init = &map.const_expr(init.clone())?;
+                    globals.global(ty, &init);
                 }
             }
         }
@@ -743,26 +733,27 @@ impl<'a> Module<'a> {
             .collect::<HashSet<_>>();
 
         for (i, func) in self.live_funcs() {
-            let mut body = match &func.def {
+            let body = match &func.def {
                 Definition::Import(..) => continue,
-                Definition::Local(body) => body.get_binary_reader(),
+                Definition::Local(body) => body,
             };
-            let mut locals = Vec::new();
-            for _ in 0..body.read_var_u32()? {
-                let cnt = body.read_var_u32()?;
-                let ty = body.read()?;
-                locals.push((cnt, map.valty(ty)));
-            }
-            // Prepend an `allocate_stack` call to all exports if we're lazily allocating the stack.
-            if let (Some(lazy_stack_init_index), true) =
-                (lazy_stack_init_index, exported_funcs.contains(&i))
-            {
-                Instruction::Call(lazy_stack_init_index).encode(&mut map.buf);
+
+            match (lazy_stack_init_index, exported_funcs.contains(&i)) {
+                // Prepend an `allocate_stack` call to all exports if we're
+                // lazily allocating the stack.
+                (Some(lazy_stack_init_index), true) => {
+                    let mut func = map.new_function_with_parsed_locals(&body)?;
+                    func.instruction(&Instruction::Call(lazy_stack_init_index));
+                    let mut reader = body.get_operators_reader()?;
+                    while !reader.eof() {
+                        map.parse_instruction(&mut func, &mut reader)?;
+                    }
+                    code.function(&func);
+                }
+                _ => {
+                    map.parse_function_body(&mut code, body.clone())?;
+                }
             }
-            let bytes = map.operators(body)?;
-            let mut func = wasm_encoder::Function::new(locals);
-            func.raw(bytes);
-            code.function(&func);
         }
 
         if lazy_stack_init_index.is_some() {
@@ -1061,178 +1052,28 @@ struct Encoder {
     memories: Remap,
     globals: Remap,
     tables: Remap,
-    buf: Vec<u8>,
 }
 
-impl Encoder {
-    fn operators(&mut self, mut reader: BinaryReader<'_>) -> Result<Vec<u8>> {
-        while !reader.eof() {
-            reader.visit_operator(self)?;
-        }
-        Ok(mem::take(&mut self.buf))
-    }
-
-    fn memarg(&self, ty: MemArg) -> wasm_encoder::MemArg {
-        wasm_encoder::MemArg {
-            offset: ty.offset,
-            align: ty.align.into(),
-            memory_index: self.memories.remap(ty.memory),
-        }
-    }
+impl Reencode for Encoder {
+    type Error = Infallible;
 
-    fn ordering(&self, ord: Ordering) -> wasm_encoder::Ordering {
-        match ord {
-            Ordering::AcqRel => wasm_encoder::Ordering::AcqRel,
-            Ordering::SeqCst => wasm_encoder::Ordering::SeqCst,
-        }
+    fn type_index(&mut self, i: u32) -> u32 {
+        self.types.remap(i)
     }
-
-    fn blockty(&self, ty: BlockType) -> wasm_encoder::BlockType {
-        match ty {
-            BlockType::Empty => wasm_encoder::BlockType::Empty,
-            BlockType::Type(ty) => wasm_encoder::BlockType::Result(self.valty(ty)),
-            BlockType::FuncType(ty) => wasm_encoder::BlockType::FunctionType(self.types.remap(ty)),
-        }
+    fn function_index(&mut self, i: u32) -> u32 {
+        self.funcs.remap(i)
     }
-
-    fn valty(&self, ty: wasmparser::ValType) -> wasm_encoder::ValType {
-        match ty {
-            wasmparser::ValType::I32 => wasm_encoder::ValType::I32,
-            wasmparser::ValType::I64 => wasm_encoder::ValType::I64,
-            wasmparser::ValType::F32 => wasm_encoder::ValType::F32,
-            wasmparser::ValType::F64 => wasm_encoder::ValType::F64,
-            wasmparser::ValType::V128 => wasm_encoder::ValType::V128,
-            wasmparser::ValType::Ref(rt) => wasm_encoder::ValType::Ref(self.refty(rt)),
-        }
+    fn memory_index(&mut self, i: u32) -> u32 {
+        self.memories.remap(i)
     }
-
-    fn refty(&self, rt: wasmparser::RefType) -> wasm_encoder::RefType {
-        wasm_encoder::RefType {
-            nullable: rt.is_nullable(),
-            heap_type: self.heapty(rt.heap_type()),
-        }
+    fn global_index(&mut self, i: u32) -> u32 {
+        self.globals.remap(i)
     }
-
-    fn heapty(&self, ht: wasmparser::HeapType) -> wasm_encoder::HeapType {
-        match ht {
-            HeapType::Concrete(idx) => {
-                wasm_encoder::HeapType::Concrete(self.types.remap(idx.as_module_index().unwrap()))
-            }
-            HeapType::Abstract { shared, ty } => {
-                let ty = ty.into();
-                wasm_encoder::HeapType::Abstract { shared, ty }
-            }
-        }
+    fn table_index(&mut self, i: u32) -> u32 {
+        self.tables.remap(i)
     }
 }
 
-// This is a helper macro to translate all `wasmparser` instructions to
-// `wasm-encoder` instructions without having to list out every single
-// instruction itself.
-//
-// The general goal of this macro is to have O(unique instruction payload)
-// number of cases while also simultaneously adapting between the styles of
-// wasmparser and wasm-encoder.
-macro_rules! define_encode {
-    ($(@$p:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
-        $(
-            fn $visit(&mut self $(, $($arg: $argty),*)?)  {
-                #[allow(unused_imports)]
-                use wasm_encoder::Instruction::*;
-                $(
-                    $(
-                        let $arg = define_encode!(map self $arg $arg);
-                    )*
-                )?
-                let insn = define_encode!(mk $op $($($arg)*)?);
-                insn.encode(&mut self.buf);
-            }
-        )*
-    };
-
-    // No-payload instructions are named the same in wasmparser as they are in
-    // wasm-encoder
-    (mk $op:ident) => ($op);
-
-    // Instructions which need "special care" to map from wasmparser to
-    // wasm-encoder
-    (mk BrTable $arg:ident) => ({
-        BrTable($arg.0, $arg.1)
-    });
-    (mk TryTable $try_table:ident) => ({
-        let _ = $try_table;
-        unimplemented_try_table()
-    });
-    (mk I32Const $v:ident) => (I32Const($v));
-    (mk I64Const $v:ident) => (I64Const($v));
-    (mk F32Const $v:ident) => (F32Const(f32::from_bits($v.bits())));
-    (mk F64Const $v:ident) => (F64Const(f64::from_bits($v.bits())));
-    (mk V128Const $v:ident) => (V128Const($v.i128()));
-
-    // Catch-all for the translation of one payload argument which is typically
-    // represented as a tuple-enum in wasm-encoder.
-    (mk $op:ident $arg:ident) => ($op($arg));
-
-    // Catch-all of everything else where the wasmparser fields are simply
-    // translated to wasm-encoder fields.
-    (mk $op:ident $($arg:ident)*) => ($op { $($arg),* });
-
-    // Individual cases of mapping one argument type to another, similar to the
-    // `define_visit` macro above.
-    (map $self:ident $arg:ident memarg) => {$self.memarg($arg)};
-    (map $self:ident $arg:ident ordering) => {$self.ordering($arg)};
-    (map $self:ident $arg:ident blockty) => {$self.blockty($arg)};
-    (map $self:ident $arg:ident hty) => {$self.heapty($arg)};
-    (map $self:ident $arg:ident from_ref_type) => {$self.refty($arg)};
-    (map $self:ident $arg:ident to_ref_type) => {$self.refty($arg)};
-    (map $self:ident $arg:ident tag_index) => {$arg};
-    (map $self:ident $arg:ident relative_depth) => {$arg};
-    (map $self:ident $arg:ident function_index) => {$self.funcs.remap($arg)};
-    (map $self:ident $arg:ident global_index) => {$self.globals.remap($arg)};
-    (map $self:ident $arg:ident mem) => {$self.memories.remap($arg)};
-    (map $self:ident $arg:ident src_mem) => {$self.memories.remap($arg)};
-    (map $self:ident $arg:ident dst_mem) => {$self.memories.remap($arg)};
-    (map $self:ident $arg:ident table) => {$self.tables.remap($arg)};
-    (map $self:ident $arg:ident table_index) => {$self.tables.remap($arg)};
-    (map $self:ident $arg:ident src_table) => {$self.tables.remap($arg)};
-    (map $self:ident $arg:ident dst_table) => {$self.tables.remap($arg)};
-    (map $self:ident $arg:ident type_index) => {$self.types.remap($arg)};
-    (map $self:ident $arg:ident array_type_index) => {$self.types.remap($arg)};
-    (map $self:ident $arg:ident array_type_index_dst) => {$self.types.remap($arg)};
-    (map $self:ident $arg:ident array_type_index_src) => {$self.types.remap($arg)};
-    (map $self:ident $arg:ident struct_type_index) => {$self.types.remap($arg)};
-    (map $self:ident $arg:ident ty) => {$self.valty($arg)};
-    (map $self:ident $arg:ident local_index) => {$arg};
-    (map $self:ident $arg:ident lane) => {$arg};
-    (map $self:ident $arg:ident lanes) => {$arg};
-    (map $self:ident $arg:ident elem_index) => {$arg};
-    (map $self:ident $arg:ident data_index) => {$arg};
-    (map $self:ident $arg:ident array_elem_index) => {$arg};
-    (map $self:ident $arg:ident array_data_index) => {$arg};
-    (map $self:ident $arg:ident table_byte) => {$arg};
-    (map $self:ident $arg:ident mem_byte) => {$arg};
-    (map $self:ident $arg:ident value) => {$arg};
-    (map $self:ident $arg:ident array_size) => {$arg};
-    (map $self:ident $arg:ident field_index) => {$arg};
-    (map $self:ident $arg:ident from_type_nullable) => {$arg};
-    (map $self:ident $arg:ident to_type_nullable) => {$arg};
-    (map $self:ident $arg:ident try_table) => {$arg};
-    (map $self:ident $arg:ident targets) => ((
-        $arg.targets().map(|i| i.unwrap()).collect::<Vec<_>>().into(),
-        $arg.default(),
-    ));
-}
-
-fn unimplemented_try_table() -> wasm_encoder::Instruction<'static> {
-    unimplemented!()
-}
-
-impl<'a> VisitOperator<'a> for Encoder {
-    type Output = ();
-
-    wasmparser::for_each_operator!(define_encode);
-}
-
 // Minimal definition of a bit vector necessary for the liveness calculations
 // above.
 mod bitvec {
diff --git a/fuzz/fuzz_targets/run.rs b/fuzz/fuzz_targets/run.rs
index b9b196a8..7ff50dfe 100644
--- a/fuzz/fuzz_targets/run.rs
+++ b/fuzz/fuzz_targets/run.rs
@@ -79,4 +79,5 @@ run_fuzzers! {
     print: unstructured,
     roundtrip: string,
     text_parser: string,
+    reencode: unstructured,
 }
diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs
index 32c2f8f6..7d140cb6 100644
--- a/fuzz/src/lib.rs
+++ b/fuzz/src/lib.rs
@@ -7,6 +7,7 @@ pub mod incremental_parse;
 pub mod mutate;
 pub mod no_traps;
 pub mod print;
+pub mod reencode;
 pub mod roundtrip;
 pub mod roundtrip_wit;
 pub mod text_parser;
diff --git a/fuzz/src/reencode.rs b/fuzz/src/reencode.rs
new file mode 100644
index 00000000..fef897bf
--- /dev/null
+++ b/fuzz/src/reencode.rs
@@ -0,0 +1,16 @@
+use arbitrary::{Result, Unstructured};
+use wasm_encoder::reencode::{Reencode, RoundtripReencoder};
+
+pub fn run(u: &mut Unstructured<'_>) -> Result<()> {
+    let (module1, _) = super::generate_valid_module(u, |_, _| Ok(()))?;
+
+    let mut module2 = Default::default();
+    RoundtripReencoder
+        .parse_core_module(&mut module2, wasmparser::Parser::new(0), &module1)
+        .unwrap();
+
+    let module2 = module2.finish();
+    assert_eq!(module1, module2);
+
+    Ok(())
+}


Test patch:
diff --git a/crates/wit-component/tests/interfaces/flags.wat b/crates/wit-component/tests/interfaces/flags.wat
index 7c0aa398..61a6ea97 100644
--- a/crates/wit-component/tests/interfaces/flags.wat
+++ b/crates/wit-component/tests/interfaces/flags.wat
@@ -15,22 +15,18 @@
           (export (;9;) "flag16" (type (eq 8)))
           (type (;10;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15" "b16" "b17" "b18" "b19" "b20" "b21" "b22" "b23" "b24" "b25" "b26" "b27" "b28" "b29" "b30" "b31"))
           (export (;11;) "flag32" (type (eq 10)))
-          (type (;12;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15" "b16" "b17" "b18" "b19" "b20" "b21" "b22" "b23" "b24" "b25" "b26" "b27" "b28" "b29" "b30" "b31" "b32" "b33" "b34" "b35" "b36" "b37" "b38" "b39" "b40" "b41" "b42" "b43" "b44" "b45" "b46" "b47" "b48" "b49" "b50" "b51" "b52" "b53" "b54" "b55" "b56" "b57" "b58" "b59" "b60" "b61" "b62" "b63"))
-          (export (;13;) "flag64" (type (eq 12)))
-          (type (;14;) (func (param "x" 1) (result 1)))
-          (export (;0;) "roundtrip-flag1" (func (type 14)))
-          (type (;15;) (func (param "x" 3) (result 3)))
-          (export (;1;) "roundtrip-flag2" (func (type 15)))
-          (type (;16;) (func (param "x" 5) (result 5)))
-          (export (;2;) "roundtrip-flag4" (func (type 16)))
-          (type (;17;) (func (param "x" 7) (result 7)))
-          (export (;3;) "roundtrip-flag8" (func (type 17)))
-          (type (;18;) (func (param "x" 9) (result 9)))
-          (export (;4;) "roundtrip-flag16" (func (type 18)))
-          (type (;19;) (func (param "x" 11) (result 11)))
-          (export (;5;) "roundtrip-flag32" (func (type 19)))
-          (type (;20;) (func (param "x" 13) (result 13)))
-          (export (;6;) "roundtrip-flag64" (func (type 20)))
+          (type (;12;) (func (param "x" 1) (result 1)))
+          (export (;0;) "roundtrip-flag1" (func (type 12)))
+          (type (;13;) (func (param "x" 3) (result 3)))
+          (export (;1;) "roundtrip-flag2" (func (type 13)))
+          (type (;14;) (func (param "x" 5) (result 5)))
+          (export (;2;) "roundtrip-flag4" (func (type 14)))
+          (type (;15;) (func (param "x" 7) (result 7)))
+          (export (;3;) "roundtrip-flag8" (func (type 15)))
+          (type (;16;) (func (param "x" 9) (result 9)))
+          (export (;4;) "roundtrip-flag16" (func (type 16)))
+          (type (;17;) (func (param "x" 11) (result 11)))
+          (export (;5;) "roundtrip-flag32" (func (type 17)))
         )
       )
       (export (;0;) "foo:flags/imports" (instance (type 0)))
@@ -55,22 +51,18 @@
               (export (;9;) "flag16" (type (eq 8)))
               (type (;10;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15" "b16" "b17" "b18" "b19" "b20" "b21" "b22" "b23" "b24" "b25" "b26" "b27" "b28" "b29" "b30" "b31"))
               (export (;11;) "flag32" (type (eq 10)))
-              (type (;12;) (flags "b0" "b1" "b2" "b3" "b4" "b5" "b6" "b7" "b8" "b9" "b10" "b11" "b12" "b13" "b14" "b15" "b16" "b17" "b18" "b19" "b20" "b21" "b22" "b23" "b24" "b25" "b26" "b27" "b28" "b29" "b30" "b31" "b32" "b33" "b34" "b35" "b36" "b37" "b38" "b39" "b40" "b41" "b42" "b43" "b44" "b45" "b46" "b47" "b48" "b49" "b50" "b51" "b52" "b53" "b54" "b55" "b56" "b57" "b58" "b59" "b60" "b61" "b62" "b63"))
-              (export (;13;) "flag64" (type (eq 12)))
-              (type (;14;) (func (param "x" 1) (result 1)))
-              (export (;0;) "roundtrip-flag1" (func (type 14)))
-              (type (;15;) (func (param "x" 3) (result 3)))
-              (export (;1;) "roundtrip-flag2" (func (type 15)))
-              (type (;16;) (func (param "x" 5) (result 5)))
-              (export (;2;) "roundtrip-flag4" (func (type 16)))
-              (type (;17;) (func (param "x" 7) (result 7)))
-              (export (;3;) "roundtrip-flag8" (func (type 17)))
-              (type (;18;) (func (param "x" 9) (result 9)))
-              (export (;4;) "roundtrip-flag16" (func (type 18)))
-              (type (;19;) (func (param "x" 11) (result 11)))
-              (export (;5;) "roundtrip-flag32" (func (type 19)))
-              (type (;20;) (func (param "x" 13) (result 13)))
-              (export (;6;) "roundtrip-flag64" (func (type 20)))
+              (type (;12;) (func (param "x" 1) (result 1)))
+              (export (;0;) "roundtrip-flag1" (func (type 12)))
+              (type (;13;) (func (param "x" 3) (result 3)))
+              (export (;1;) "roundtrip-flag2" (func (type 13)))
+              (type (;14;) (func (param "x" 5) (result 5)))
+              (export (;2;) "roundtrip-flag4" (func (type 14)))
+              (type (;15;) (func (param "x" 7) (result 7)))
+              (export (;3;) "roundtrip-flag8" (func (type 15)))
+              (type (;16;) (func (param "x" 9) (result 9)))
+              (export (;4;) "roundtrip-flag16" (func (type 16)))
+              (type (;17;) (func (param "x" 11) (result 11)))
+              (export (;5;) "roundtrip-flag32" (func (type 17)))
             )
           )
           (import "foo:flags/imports" (instance (;0;) (type 0)))
diff --git a/crates/wit-component/tests/interfaces/flags.wit b/crates/wit-component/tests/interfaces/flags.wit
index 9542f96e..75f16cb3 100644
--- a/crates/wit-component/tests/interfaces/flags.wit
+++ b/crates/wit-component/tests/interfaces/flags.wit
@@ -82,73 +82,6 @@ interface imports {
     b31,
   }
 
-  flags flag64 {
-    b0,
-    b1,
-    b2,
-    b3,
-    b4,
-    b5,
-    b6,
-    b7,
-    b8,
-    b9,
-    b10,
-    b11,
-    b12,
-    b13,
-    b14,
-    b15,
-    b16,
-    b17,
-    b18,
-    b19,
-    b20,
-    b21,
-    b22,
-    b23,
-    b24,
-    b25,
-    b26,
-    b27,
-    b28,
-    b29,
-    b30,
-    b31,
-    b32,
-    b33,
-    b34,
-    b35,
-    b36,
-    b37,
-    b38,
-    b39,
-    b40,
-    b41,
-    b42,
-    b43,
-    b44,
-    b45,
-    b46,
-    b47,
-    b48,
-    b49,
-    b50,
-    b51,
-    b52,
-    b53,
-    b54,
-    b55,
-    b56,
-    b57,
-    b58,
-    b59,
-    b60,
-    b61,
-    b62,
-    b63,
-  }
-
   roundtrip-flag1: func(x: flag1) -> flag1;
 
   roundtrip-flag2: func(x: flag2) -> flag2;
@@ -160,8 +93,6 @@ interface imports {
   roundtrip-flag16: func(x: flag16) -> flag16;
 
   roundtrip-flag32: func(x: flag32) -> flag32;
-
-  roundtrip-flag64: func(x: flag64) -> flag64;
 }
 
 world flags-world {
diff --git a/crates/wit-component/tests/interfaces/flags.wit.print b/crates/wit-component/tests/interfaces/flags.wit.print
index 9542f96e..75f16cb3 100644
--- a/crates/wit-component/tests/interfaces/flags.wit.print
+++ b/crates/wit-component/tests/interfaces/flags.wit.print
@@ -82,73 +82,6 @@ interface imports {
     b31,
   }
 
-  flags flag64 {
-    b0,
-    b1,
-    b2,
-    b3,
-    b4,
-    b5,
-    b6,
-    b7,
-    b8,
-    b9,
-    b10,
-    b11,
-    b12,
-    b13,
-    b14,
-    b15,
-    b16,
-    b17,
-    b18,
-    b19,
-    b20,
-    b21,
-    b22,
-    b23,
-    b24,
-    b25,
-    b26,
-    b27,
-    b28,
-    b29,
-    b30,
-    b31,
-    b32,
-    b33,
-    b34,
-    b35,
-    b36,
-    b37,
-    b38,
-    b39,
-    b40,
-    b41,
-    b42,
-    b43,
-    b44,
-    b45,
-    b46,
-    b47,
-    b48,
-    b49,
-    b50,
-    b51,
-    b52,
-    b53,
-    b54,
-    b55,
-    b56,
-    b57,
-    b58,
-    b59,
-    b60,
-    b61,
-    b62,
-    b63,
-  }
-
   roundtrip-flag1: func(x: flag1) -> flag1;
 
   roundtrip-flag2: func(x: flag2) -> flag2;
@@ -160,8 +93,6 @@ interface imports {
   roundtrip-flag16: func(x: flag16) -> flag16;
 
   roundtrip-flag32: func(x: flag32) -> flag32;
-
-  roundtrip-flag64: func(x: flag64) -> flag64;
 }
 
 world flags-world {
diff --git a/tests/local/component-model/more-flags.wast b/tests/local/component-model/more-flags.wast
new file mode 100644
index 00000000..6d17e450
--- /dev/null
+++ b/tests/local/component-model/more-flags.wast
@@ -0,0 +1,37 @@
+(component
+  (type (flags
+    "f1"
+    "f2"
+    "f3"
+    "f4"
+    "f5"
+    "f6"
+    "f7"
+    "f8"
+    "f9"
+    "f10"
+    "f11"
+    "f12"
+    "f13"
+    "f14"
+    "f15"
+    "f16"
+    "f17"
+    "f18"
+    "f19"
+    "f20"
+    "f21"
+    "f22"
+    "f23"
+    "f24"
+    "f25"
+    "f26"
+    "f27"
+    "f28"
+    "f29"
+    "f30"
+    "f31"
+    "f32"
+    "f33"
+  ))
+)
diff --git a/tests/local/component-model/types.wast b/tests/local/component-model/types.wast
index 628ec825..88fbd2d3 100644
--- a/tests/local/component-model/types.wast
+++ b/tests/local/component-model/types.wast
@@ -323,3 +323,43 @@
     ))
   )
 )
+
+(assert_invalid
+  (component
+    (type (flags
+      "f1"
+      "f2"
+      "f3"
+      "f4"
+      "f5"
+      "f6"
+      "f7"
+      "f8"
+      "f9"
+      "f10"
+      "f11"
+      "f12"
+      "f13"
+      "f14"
+      "f15"
+      "f16"
+      "f17"
+      "f18"
+      "f19"
+      "f20"
+      "f21"
+      "f22"
+      "f23"
+      "f24"
+      "f25"
+      "f26"
+      "f27"
+      "f28"
+      "f29"
+      "f30"
+      "f31"
+      "f32"
+      "f33"
+    ))
+  )
+  "cannot have more than 32 flags")
diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs
index 61620033..66fdc1e4 100644
--- a/tests/roundtrip.rs
+++ b/tests/roundtrip.rs
@@ -578,7 +578,8 @@ impl TestState {
         let mut features = WasmFeatures::all()
             & !WasmFeatures::SHARED_EVERYTHING_THREADS
             & !WasmFeatures::COMPONENT_MODEL
-            & !WasmFeatures::COMPONENT_MODEL_NESTED_NAMES;
+            & !WasmFeatures::COMPONENT_MODEL_NESTED_NAMES
+            & !WasmFeatures::COMPONENT_MODEL_MORE_FLAGS;
         for part in test.iter().filter_map(|t| t.to_str()) {
             match part {
                 "testsuite" => {
@@ -623,6 +624,9 @@ impl TestState {
                 "import-extended.wast" => {
                     features.insert(WasmFeatures::COMPONENT_MODEL_NESTED_NAMES);
                 }
+                "more-flags.wast" => {
+                    features.insert(WasmFeatures::COMPONENT_MODEL_MORE_FLAGS);
+                }
                 _ => {}
             }
         }
diff --git a/tests/snapshots/local/component-model/more-flags.wast/0.print b/tests/snapshots/local/component-model/more-flags.wast/0.print
new file mode 100644
index 00000000..5e23480a
--- /dev/null
+++ b/tests/snapshots/local/component-model/more-flags.wast/0.print
@@ -0,0 +1,3 @@
+(component
+  (type (;0;) (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" "f9" "f10" "f11" "f12" "f13" "f14" "f15" "f16" "f17" "f18" "f19" "f20" "f21" "f22" "f23" "f24" "f25" "f26" "f27" "f28" "f29" "f30" "f31" "f32" "f33"))
+)