@@ -99,6 +99,47 @@ macro_rules! define_config {
9999 /// ```
100100 pub exports: Option <Vec <u8 >>,
101101
102+ /// If provided, the generated module will have imports and exports
103+ /// with exactly the same names and types as those in the provided
104+ /// WebAssembly module.
105+ ///
106+ /// Defaults to `None` which means arbitrary imports and exports will be
107+ /// generated.
108+ ///
109+ /// Note that [`Self::available_imports`] and [`Self::exports`] are
110+ /// ignored when `module_shape` is enabled.
111+ ///
112+ /// The provided value must be a valid binary encoding of a
113+ /// WebAssembly module. `wasm-smith` will panic if the module cannot
114+ /// be parsed.
115+ ///
116+ /// # Module Limits
117+ ///
118+ /// All types, functions, globals, memories, tables, tags, imports, and exports
119+ /// that are needed to provide the required imports and exports will be generated,
120+ /// even if it causes the resulting module to exceed the limits defined in
121+ /// [`Self::max_type_size`], [`Self::max_types`], [`Self::max_funcs`],
122+ /// [`Self::max_globals`], [`Self::max_memories`], [`Self::max_tables`],
123+ /// [`Self::max_tags`], [`Self::max_imports`], or [`Self::max_exports`].
124+ ///
125+ /// # Example
126+ ///
127+ /// As for [`Self::available_imports`] and [`Self::exports`], the
128+ /// `wat` crate can be used to provide a human-readable description of the
129+ /// module shape:
130+ ///
131+ /// ```rust
132+ /// Some(wat::parse_str(r#"
133+ /// (module
134+ /// (import "env" "ping" (func (param i32)))
135+ /// (import "env" "memory" (memory 1))
136+ /// (func (export "foo") (param anyref) (result structref) unreachable)
137+ /// (global (export "bar") arrayref (ref.null array))
138+ /// )
139+ /// "#));
140+ /// ```
141+ pub module_shape: Option <Vec <u8 >>,
142+
102143 $(
103144 $( #[ $field_attr] ) *
104145 pub $field: $field_ty,
@@ -110,6 +151,7 @@ macro_rules! define_config {
110151 Config {
111152 available_imports: None ,
112153 exports: None ,
154+ module_shape: None ,
113155
114156 $(
115157 $field: $default,
@@ -173,6 +215,31 @@ macro_rules! define_config {
173215 #[ cfg_attr( feature = "clap" , clap( long) ) ]
174216 exports: Option <std:: path:: PathBuf >,
175217
218+ /// If provided, the generated module will have imports and exports
219+ /// with exactly the same names and types as those in the provided
220+ /// WebAssembly module.
221+ ///
222+ /// Defaults to `None` which means arbitrary imports and exports will be
223+ /// generated.
224+ ///
225+ /// Note that [`Self::available_imports`] and [`Self::exports`] are
226+ /// ignored when `module_shape` is enabled.
227+ ///
228+ /// The provided value must be a valid binary encoding of a
229+ /// WebAssembly module. `wasm-smith` will panic if the module cannot
230+ /// be parsed.
231+ ///
232+ /// # Module Limits
233+ ///
234+ /// All types, functions, globals, memories, tables, tags, imports, and exports
235+ /// that are needed to provide the required imports and exports will be generated,
236+ /// even if it causes the resulting module to exceed the limits defined in
237+ /// [`Self::max_type_size`], [`Self::max_types`], [`Self::max_funcs`],
238+ /// [`Self::max_globals`], [`Self::max_memories`], [`Self::max_tables`],
239+ /// [`Self::max_tags`], [`Self::max_imports`], or [`Self::max_exports`].
240+ #[ cfg_attr( feature = "clap" , clap( long) ) ]
241+ module_shape: Option <std:: path:: PathBuf >,
242+
176243 $(
177244 $( #[ $field_attr] ) *
178245 #[ cfg_attr( feature = "clap" , clap( long) ) ]
@@ -185,6 +252,7 @@ macro_rules! define_config {
185252 Self {
186253 available_imports: self . available_imports. or( other. available_imports) ,
187254 exports: self . exports. or( other. exports) ,
255+ module_shape: self . module_shape. or( other. module_shape) ,
188256
189257 $(
190258 $field: self . $field. or( other. $field) ,
@@ -213,6 +281,13 @@ macro_rules! define_config {
213281 } else {
214282 None
215283 } ,
284+ module_shape: if let Some ( file) = config
285+ . module_shape
286+ . as_ref( ) {
287+ Some ( wat:: parse_file( file) ?)
288+ } else {
289+ None
290+ } ,
216291
217292 $(
218293 $field: config. $field. unwrap_or( default . $field) ,
@@ -230,9 +305,13 @@ macro_rules! define_config {
230305 if config. exports. is_some( ) {
231306 bail!( "cannot serialize configuration with `exports`" ) ;
232307 }
308+ if config. module_shape. is_some( ) {
309+ bail!( "cannot serialize configuration with `module_shape`" ) ;
310+ }
233311 Ok ( InternalOptionalConfig {
234312 available_imports: None ,
235313 exports: None ,
314+ module_shape: None ,
236315 $( $field: Some ( config. $field. clone( ) ) , ) *
237316 } )
238317 }
@@ -788,6 +867,7 @@ impl<'a> Arbitrary<'a> for Config {
788867 canonicalize_nans : false ,
789868 available_imports : None ,
790869 exports : None ,
870+ module_shape : None ,
791871 export_everything : false ,
792872 generate_custom_sections : false ,
793873 allow_invalid_funcs : false ,
@@ -841,6 +921,12 @@ impl Config {
841921 if !self . threads_enabled {
842922 self . shared_everything_threads_enabled = false ;
843923 }
924+
925+ // If module_shape is present then disable available_imports and exports.
926+ if self . module_shape . is_some ( ) {
927+ self . available_imports = None ;
928+ self . exports = None ;
929+ }
844930 }
845931
846932 /// Returns the set of features that are necessary for validating against
0 commit comments