/src/wasm-tools/crates/wit-smith/src/generate.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::config::Config; |
2 | | use arbitrary::{Arbitrary, Result, Unstructured}; |
3 | | use indexmap::IndexMap; |
4 | | use semver::Version; |
5 | | use std::collections::hash_map::{Entry, HashMap}; |
6 | | use std::collections::HashSet; |
7 | | use std::fmt::Write; |
8 | | use std::rc::Rc; |
9 | | use std::str; |
10 | | use wit_parser::*; |
11 | | |
12 | | pub struct Generator { |
13 | | config: Config, |
14 | | packages: PackageList, |
15 | | next_interface_id: u32, |
16 | | } |
17 | | |
18 | | type TypeList = Vec<Type>; |
19 | | type InterfaceList = IndexMap<String, FileInterface>; |
20 | | type PackageList = Vec<(PackageName, InterfaceList)>; |
21 | | |
22 | | struct InterfaceGenerator<'a> { |
23 | | generator: &'a Generator, |
24 | | file: &'a mut File, |
25 | | config: &'a Config, |
26 | | unique_names: HashSet<String>, |
27 | | types_in_interface: TypeList, |
28 | | } |
29 | | |
30 | | #[derive(Clone)] |
31 | | struct Type { |
32 | | name: String, |
33 | | size: usize, |
34 | | is_resource: bool, |
35 | | } |
36 | | |
37 | | pub struct Package { |
38 | | pub name: PackageName, |
39 | | pub sources: SourceMap, |
40 | | } |
41 | | |
42 | | #[derive(Clone)] |
43 | | pub struct PackageName { |
44 | | pub namespace: String, |
45 | | pub name: String, |
46 | | pub version: Option<Version>, |
47 | | } |
48 | | |
49 | | impl Generator { |
50 | 3.56k | pub fn new(config: Config) -> Generator { |
51 | 3.56k | Generator { |
52 | 3.56k | config, |
53 | 3.56k | packages: Default::default(), |
54 | 3.56k | next_interface_id: 0, |
55 | 3.56k | } |
56 | 3.56k | } |
57 | | |
58 | 3.56k | pub fn generate(&mut self, u: &mut Unstructured<'_>) -> Result<Vec<Package>> { |
59 | 3.56k | let mut packages = Vec::new(); |
60 | 3.56k | let mut names = HashSet::new(); |
61 | 7.12k | while packages.len() < self.config.max_packages && packages.is_empty() { |
62 | 3.56k | let (pkg, interfaces) = self.gen_package(u, &mut names)?; |
63 | 3.56k | if interfaces.len() > 0 { |
64 | 1.92k | self.packages.push((pkg.name.clone(), interfaces)); |
65 | 1.92k | } |
66 | 3.56k | packages.push(pkg); |
67 | | } |
68 | 3.56k | Ok(packages) |
69 | 3.56k | } |
70 | | |
71 | 3.56k | fn gen_package( |
72 | 3.56k | &mut self, |
73 | 3.56k | u: &mut Unstructured<'_>, |
74 | 3.56k | names: &mut HashSet<String>, |
75 | 3.56k | ) -> Result<(Package, InterfaceList)> { |
76 | 3.56k | let namespace = gen_unique_name(u, names)?; |
77 | 3.56k | let name = gen_unique_name(u, names)?; |
78 | 3.56k | let version = if u.arbitrary()? { |
79 | 2.78k | Some(gen_version(u)?) |
80 | | } else { |
81 | 774 | None |
82 | | }; |
83 | 3.56k | let mut ret = Package { |
84 | 3.56k | name: PackageName { |
85 | 3.56k | namespace, |
86 | 3.56k | name, |
87 | 3.56k | version, |
88 | 3.56k | }, |
89 | 3.56k | sources: SourceMap::new(), |
90 | 3.56k | }; |
91 | | |
92 | 28.0k | #[derive(Arbitrary, Clone)] <<wit_smith::generate::Generator>::gen_package::Generate as arbitrary::Arbitrary>::arbitrary::{closure#0} Line | Count | Source | 92 | 9.08k | #[derive(Arbitrary, Clone)] |
<<wit_smith::generate::Generator>::gen_package::Generate as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 92 | 18.9k | #[derive(Arbitrary, Clone)] |
<<wit_smith::generate::Generator>::gen_package::Generate as arbitrary::Arbitrary>::arbitrary::{closure#2} Line | Count | Source | 92 | 9.08k | #[derive(Arbitrary, Clone)] |
Unexecuted instantiation: <<wit_smith::generate::Generator>::gen_package::Generate as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <<wit_smith::generate::Generator>::gen_package::Generate as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <<wit_smith::generate::Generator>::gen_package::Generate as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <<wit_smith::generate::Generator>::gen_package::Generate as arbitrary::Arbitrary>::size_hint::{closure#0} |
93 | | enum Generate { |
94 | | Interface, |
95 | | Use, |
96 | | World, |
97 | | Done, |
98 | | } |
99 | | |
100 | 3.56k | let mut items = 0; |
101 | 3.56k | let mut empty = true; |
102 | 3.56k | let mut files = vec![File::default()]; |
103 | 3.56k | let mut package_names = HashSet::new(); |
104 | 3.56k | let mut package = File::default(); |
105 | 3.56k | log::debug!("===================== new package ===================="); |
106 | 26.5k | while items < self.config.max_pkg_items { |
107 | 23.6k | items += 1; |
108 | 23.6k | let max = if files.len() < self.config.max_files_per_package { |
109 | 17.5k | files.len() + 1 |
110 | | } else { |
111 | 6.13k | files.len() |
112 | | }; |
113 | 23.6k | let i = u.int_in_range(0..=max)?; |
114 | 23.6k | let file = match files.get_mut(i) { |
115 | 18.0k | Some(file) => file, |
116 | | None => { |
117 | 5.62k | files.push(File { |
118 | 5.62k | items: Vec::new(), |
119 | 5.62k | namespace: package |
120 | 5.62k | .interfaces |
121 | 5.62k | .iter() |
122 | 5.62k | .map(|(k, _)| (k.clone(), Definition::Package)) |
123 | 5.62k | .collect(), |
124 | 5.62k | interfaces: package.interfaces.clone(), |
125 | 5.62k | }); |
126 | 5.62k | files.last_mut().unwrap() |
127 | | } |
128 | | }; |
129 | | |
130 | | // Only generate Use/Done if we've already generated a world or interface. This ensures |
131 | | // that we never generate empty packages, which aren't representable. |
132 | 23.6k | let generate = if empty { |
133 | 4.64k | u.choose(&[Generate::World, Generate::Interface])?.clone() |
134 | | } else { |
135 | 18.9k | u.arbitrary()? |
136 | | }; |
137 | | |
138 | 23.6k | match generate { |
139 | | Generate::World => { |
140 | 6.95k | let name = file.gen_unique_package_name(u, &mut package_names)?; |
141 | 6.95k | log::debug!("new world `{name}` in {i}"); |
142 | 6.95k | let world = self.gen_world(u, &name, file)?; |
143 | 6.95k | file.items.push(world); |
144 | 6.95k | |
145 | 6.95k | empty = false; |
146 | | } |
147 | | Generate::Interface => { |
148 | 14.7k | let name = file.gen_unique_package_name(u, &mut package_names)?; |
149 | 14.7k | log::debug!("new interface `{name}` in {i}"); |
150 | 14.7k | let id = self.next_interface_id; |
151 | 14.7k | self.next_interface_id += 1; |
152 | 14.7k | let (src, types) = self.gen_interface(u, Some(&name), file)?; |
153 | 14.7k | file.items.push(src); |
154 | 14.7k | if types.is_empty() { |
155 | 11.4k | continue; |
156 | 3.32k | } |
157 | 3.32k | let interface = FileInterface { |
158 | 3.32k | name, |
159 | 3.32k | id, |
160 | 3.32k | types: Rc::new(types), |
161 | 3.32k | }; |
162 | 3.32k | |
163 | 3.32k | // This interface is defined at the package level, and it |
164 | 3.32k | // must be unique. |
165 | 3.32k | let prev = package |
166 | 3.32k | .interfaces |
167 | 3.32k | .insert(interface.name.clone(), interface.clone()); |
168 | 3.32k | assert!(prev.is_none()); |
169 | | |
170 | | // This is also defined at the file level, and it must be |
171 | | // unique here too. |
172 | 3.32k | let prev = file |
173 | 3.32k | .interfaces |
174 | 3.32k | .insert(interface.name.clone(), interface.clone()); |
175 | 3.32k | assert!(prev.is_none()); |
176 | | |
177 | | // Insert the definition into all other files as well. |
178 | 7.82k | for file in files.iter_mut() { |
179 | 7.82k | file.insert_definition(interface.clone()); |
180 | 7.82k | } |
181 | | |
182 | 3.32k | empty = false; |
183 | | } |
184 | | Generate::Use => { |
185 | 1.29k | let mut piece = String::new(); |
186 | 1.29k | piece.push_str("use "); |
187 | 1.29k | let (name, id, types) = match self.gen_path(u, &mut package, &mut piece)? { |
188 | 945 | Some(i) => i, |
189 | 351 | None => continue, |
190 | | }; |
191 | 945 | let name = name.to_string(); |
192 | 945 | let types = types.clone(); |
193 | 945 | let name = |
194 | 945 | if file.namespace.get(&name) == Some(&Definition::File) || u.arbitrary()? { |
195 | 769 | let name = file.gen_unique_file_name(u)?; |
196 | 769 | piece.push_str(" as %"); |
197 | 769 | piece.push_str(&name); |
198 | 769 | name |
199 | | } else { |
200 | 176 | file.namespace.insert(name.clone(), Definition::File); |
201 | 176 | name |
202 | | }; |
203 | 945 | piece.push_str(";"); |
204 | 945 | log::debug!("new use `{name}` in {i}"); |
205 | 945 | file.interfaces |
206 | 945 | .insert(name.clone(), FileInterface { name, id, types }); |
207 | 945 | file.items.push(piece) |
208 | | } |
209 | 650 | Generate::Done => break, |
210 | | }; |
211 | | } |
212 | | |
213 | 3.56k | shuffle(u, &mut files)?; |
214 | 9.18k | for file in files.iter_mut() { |
215 | 9.18k | shuffle(u, &mut file.items)?; |
216 | | } |
217 | | |
218 | 3.56k | let mut has_name = false; |
219 | 3.56k | let len = files.len(); |
220 | 9.18k | for (i, file) in files.iter_mut().enumerate() { |
221 | 9.18k | let mut s = String::new(); |
222 | 9.18k | if u.arbitrary()? || (!has_name && i == len - 1) { |
223 | 5.54k | has_name = true; |
224 | 5.54k | s.push_str("package "); |
225 | 5.54k | s.push_str("%"); |
226 | 5.54k | s.push_str(&ret.name.namespace); |
227 | 5.54k | s.push_str(":"); |
228 | 5.54k | s.push_str("%"); |
229 | 5.54k | s.push_str(&ret.name.name); |
230 | 5.54k | if let Some(version) = &ret.name.version { |
231 | 4.60k | s.push_str(&format!("@{version}")); |
232 | 4.60k | } |
233 | 5.54k | s.push_str(";\n\n"); |
234 | 3.64k | } |
235 | 22.6k | for piece in file.items.iter() { |
236 | 22.6k | s.push_str(&piece); |
237 | 22.6k | s.push_str("\n\n"); |
238 | 22.6k | } |
239 | 9.18k | log::trace!("==============================================="); |
240 | 9.18k | log::trace!("{s}"); |
241 | 9.18k | ret.sources.push(format!("wit{i}.wit").as_ref(), &s); |
242 | | } |
243 | 3.56k | Ok((ret, package.interfaces)) |
244 | 3.56k | } |
245 | | |
246 | 6.95k | fn gen_world( |
247 | 6.95k | &mut self, |
248 | 6.95k | u: &mut Unstructured<'_>, |
249 | 6.95k | name: &str, |
250 | 6.95k | file: &mut File, |
251 | 6.95k | ) -> Result<String> { |
252 | 6.95k | InterfaceGenerator::new(self, file).gen_world(u, name) |
253 | 6.95k | } |
254 | | |
255 | 14.7k | fn gen_interface( |
256 | 14.7k | &mut self, |
257 | 14.7k | u: &mut Unstructured<'_>, |
258 | 14.7k | name: Option<&str>, |
259 | 14.7k | file: &mut File, |
260 | 14.7k | ) -> Result<(String, TypeList)> { |
261 | 14.7k | let mut generator = InterfaceGenerator::new(self, file); |
262 | 14.7k | let ret = generator.gen_interface(u, name)?; |
263 | 14.7k | Ok((ret, generator.types_in_interface)) |
264 | 14.7k | } |
265 | | |
266 | 24.4k | fn gen_path<'a>( |
267 | 24.4k | &'a self, |
268 | 24.4k | u: &mut Unstructured<'_>, |
269 | 24.4k | file: &'a mut File, |
270 | 24.4k | dst: &mut String, |
271 | 24.4k | ) -> Result<Option<(&'a str, u32, &'a Rc<TypeList>)>> { |
272 | | enum Choice { |
273 | | Interfaces, |
274 | | Packages, |
275 | | } |
276 | 24.4k | let mut choices = Vec::new(); |
277 | 24.4k | if !file.interfaces.is_empty() { |
278 | 12.2k | choices.push(Choice::Interfaces); |
279 | 12.2k | } |
280 | 24.4k | if !self.packages.is_empty() { |
281 | 0 | choices.push(Choice::Packages); |
282 | 24.4k | } |
283 | 24.4k | if choices.is_empty() { |
284 | 12.2k | return Ok(None); |
285 | 12.2k | } |
286 | 12.2k | Ok(match u.choose(&choices)? { |
287 | | Choice::Interfaces => { |
288 | 12.2k | let i = u.int_in_range(0..=file.interfaces.len() - 1)?; |
289 | 12.2k | let (name, i) = file.interfaces.get_index(i).unwrap(); |
290 | 12.2k | // Once a name is used from a file's local namespace then it |
291 | 12.2k | // can't be overridden in that namespace so switch it to a file |
292 | 12.2k | // definition from whatever it previously was. |
293 | 12.2k | file.namespace.insert(name.clone(), Definition::File); |
294 | 12.2k | dst.push_str("%"); |
295 | 12.2k | dst.push_str(&i.name); |
296 | 12.2k | Some((&i.name, i.id, &i.types)) |
297 | | } |
298 | | Choice::Packages => { |
299 | 0 | let (pkg, ifaces) = u.choose(&self.packages)?; |
300 | 0 | dst.push_str("%"); |
301 | 0 | dst.push_str(&pkg.namespace); |
302 | 0 | dst.push_str(":"); |
303 | 0 | dst.push_str("%"); |
304 | 0 | dst.push_str(&pkg.name); |
305 | 0 | dst.push_str("/"); |
306 | 0 | let i = u.int_in_range(0..=ifaces.len() - 1)?; |
307 | 0 | let i = &ifaces[i]; |
308 | 0 | dst.push_str("%"); |
309 | 0 | dst.push_str(&i.name); |
310 | 0 | if let Some(version) = &pkg.version { |
311 | 0 | dst.push_str(&format!("@{version}")); |
312 | 0 | } |
313 | 0 | Some((&i.name, i.id, &i.types)) |
314 | | } |
315 | | }) |
316 | 24.4k | } |
317 | | } |
318 | | |
319 | | impl<'a> InterfaceGenerator<'a> { |
320 | 32.9k | fn new(generator: &'a Generator, file: &'a mut File) -> InterfaceGenerator<'a> { |
321 | 32.9k | InterfaceGenerator { |
322 | 32.9k | generator, |
323 | 32.9k | file, |
324 | 32.9k | config: &generator.config, |
325 | 32.9k | types_in_interface: Vec::new(), |
326 | 32.9k | // Claim the name `memory` to avoid conflicting with the canonical |
327 | 32.9k | // ABI always using a linear memory named `memory`. |
328 | 32.9k | unique_names: HashSet::from_iter(["memory".to_string()]), |
329 | 32.9k | } |
330 | 32.9k | } |
331 | | |
332 | 26.0k | fn gen_interface(&mut self, u: &mut Unstructured<'_>, name: Option<&str>) -> Result<String> { |
333 | 26.0k | let mut ret = String::new(); |
334 | 26.0k | ret.push_str("interface "); |
335 | 26.0k | if let Some(name) = name { |
336 | 14.7k | ret.push_str("%"); |
337 | 14.7k | ret.push_str(name); |
338 | 14.7k | ret.push_str(" "); |
339 | 14.7k | } |
340 | 26.0k | ret.push_str("{\n"); |
341 | | |
342 | 90.1k | #[derive(Arbitrary)] <<wit_smith::generate::InterfaceGenerator>::gen_interface::Generate as arbitrary::Arbitrary>::arbitrary::{closure#0} Line | Count | Source | 342 | 64 | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_interface::Generate as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 342 | 90.0k | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_interface::Generate as arbitrary::Arbitrary>::arbitrary::{closure#2} Line | Count | Source | 342 | 64 | #[derive(Arbitrary)] |
Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_interface::Generate as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_interface::Generate as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_interface::Generate as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_interface::Generate as arbitrary::Arbitrary>::size_hint::{closure#0} |
343 | | enum Generate { |
344 | | Use, |
345 | | Type, |
346 | | Function, |
347 | | } |
348 | | |
349 | 26.0k | let mut parts = Vec::new(); |
350 | 116k | while parts.len() < self.config.max_interface_items && u.arbitrary()? { |
351 | 90.0k | match u.arbitrary()? { |
352 | | Generate::Use => { |
353 | 13.9k | let mut part = String::new(); |
354 | 13.9k | if self.gen_use(u, &mut part)? { |
355 | 7.53k | parts.push(part); |
356 | 7.53k | } |
357 | | } |
358 | | Generate::Type => { |
359 | 59.6k | let name = self.gen_unique_name(u)?; |
360 | 59.6k | let (ty, mut typedef) = self.gen_typedef(u, &name)?; |
361 | 59.6k | let is_resource = ty.is_resource; |
362 | 59.6k | self.types_in_interface.push(ty); |
363 | 59.6k | if is_resource { |
364 | 3.93k | if u.arbitrary()? { |
365 | 3.51k | typedef.push_str(" {\n"); |
366 | 3.51k | self.gen_resource_funcs(u, &mut typedef)?; |
367 | 3.51k | typedef.push_str("}"); |
368 | 416 | } else { |
369 | 416 | typedef.push_str(";"); |
370 | 416 | } |
371 | 55.6k | } |
372 | 59.6k | parts.push(typedef); |
373 | | } |
374 | | Generate::Function => { |
375 | 16.5k | parts.push(self.gen_func(u)?); |
376 | | } |
377 | | } |
378 | | } |
379 | | |
380 | 26.0k | shuffle(u, &mut parts)?; |
381 | 109k | for part in parts { |
382 | 83.6k | ret.push_str(&part); |
383 | 83.6k | ret.push_str("\n\n"); |
384 | 83.6k | } |
385 | | |
386 | 26.0k | ret.push_str("}"); |
387 | 26.0k | Ok(ret) |
388 | 26.0k | } |
389 | | |
390 | 6.95k | fn gen_world(&mut self, u: &mut Unstructured<'_>, name: &str) -> Result<String> { |
391 | 6.95k | let mut ret = String::new(); |
392 | 6.95k | ret.push_str("world %"); |
393 | 6.95k | ret.push_str(name); |
394 | 6.95k | ret.push_str(" {\n"); |
395 | | |
396 | 15.4k | #[derive(Arbitrary, Copy, Clone)] <<wit_smith::generate::InterfaceGenerator>::gen_world::Direction as arbitrary::Arbitrary>::arbitrary::{closure#0} Line | Count | Source | 396 | 150 | #[derive(Arbitrary, Copy, Clone)] |
<<wit_smith::generate::InterfaceGenerator>::gen_world::Direction as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 396 | 15.3k | #[derive(Arbitrary, Copy, Clone)] |
<<wit_smith::generate::InterfaceGenerator>::gen_world::Direction as arbitrary::Arbitrary>::arbitrary::{closure#2} Line | Count | Source | 396 | 150 | #[derive(Arbitrary, Copy, Clone)] |
Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_world::Direction as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_world::Direction as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_world::Direction as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_world::Direction as arbitrary::Arbitrary>::size_hint::{closure#0} |
397 | | enum Direction { |
398 | | Import, |
399 | | Export, |
400 | | } |
401 | | |
402 | 27.6k | #[derive(Arbitrary)] <<wit_smith::generate::InterfaceGenerator>::gen_world::ItemKind as arbitrary::Arbitrary>::arbitrary::{closure#0} Line | Count | Source | 402 | 42 | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_world::ItemKind as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 402 | 27.6k | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_world::ItemKind as arbitrary::Arbitrary>::arbitrary::{closure#2} Line | Count | Source | 402 | 42 | #[derive(Arbitrary)] |
Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_world::ItemKind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_world::ItemKind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_world::ItemKind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_world::ItemKind as arbitrary::Arbitrary>::size_hint::{closure#0} |
403 | | enum ItemKind { |
404 | | Func(Direction), |
405 | | Interface(Direction), |
406 | | AnonInterface(Direction), |
407 | | Type, |
408 | | Use, |
409 | | } |
410 | | |
411 | 6.95k | let mut parts = Vec::new(); |
412 | 6.95k | let mut imported_interfaces = HashSet::new(); |
413 | 6.95k | let mut exported_interfaces = HashSet::new(); |
414 | 6.95k | |
415 | 6.95k | // Claim the name `memory` to avoid conflicting with the canonical |
416 | 6.95k | // ABI always using a linear memory named `memory`. |
417 | 6.95k | let mut export_names = HashSet::from_iter(["memory".to_string()]); |
418 | | |
419 | 34.5k | while parts.len() < self.config.max_world_items && !u.is_empty() && u.arbitrary()? { |
420 | 27.6k | let kind = u.arbitrary::<ItemKind>()?; |
421 | 27.6k | let (direction, named) = match kind { |
422 | 13.4k | ItemKind::Func(dir) | ItemKind::AnonInterface(dir) => (Some(dir), true), |
423 | 1.92k | ItemKind::Interface(dir) => (Some(dir), false), |
424 | 5.02k | ItemKind::Type => (None, true), |
425 | 7.28k | ItemKind::Use => (None, false), |
426 | | }; |
427 | | |
428 | 27.6k | let mut part = String::new(); |
429 | 27.6k | if let Some(dir) = direction { |
430 | 15.3k | part.push_str(match dir { |
431 | 3.88k | Direction::Import => "import ", |
432 | 11.4k | Direction::Export => "export ", |
433 | | }); |
434 | 12.3k | } |
435 | | |
436 | 27.6k | let name = if named { |
437 | 18.4k | let names = match direction { |
438 | 7.60k | Some(Direction::Import) | None => &mut self.unique_names, |
439 | 10.8k | Some(Direction::Export) => &mut export_names, |
440 | | }; |
441 | 18.4k | let name = gen_unique_name(u, names)?; |
442 | 18.4k | if direction.is_some() { |
443 | 13.4k | part.push_str("%"); |
444 | 13.4k | part.push_str(&name); |
445 | 13.4k | part.push_str(": "); |
446 | 13.4k | } |
447 | 18.4k | Some(name) |
448 | | } else { |
449 | 9.21k | None |
450 | | }; |
451 | | |
452 | 27.6k | match kind { |
453 | | ItemKind::Func(_) => { |
454 | 2.14k | self.gen_func_sig(u, &mut part, false)?; |
455 | | } |
456 | 1.92k | ItemKind::Interface(dir) => { |
457 | 1.92k | let id = match self.generator.gen_path(u, self.file, &mut part)? { |
458 | 1.06k | Some((_name, id, _types)) => id, |
459 | | // If an interface couldn't be chosen or wasn't |
460 | | // chosen then skip this import. A unique name was |
461 | | // selecteed above but we just sort of leave that |
462 | | // floating in the wild to get handled by some other |
463 | | // test case. |
464 | 857 | None => continue, |
465 | | }; |
466 | | |
467 | | // If this interface has already been imported or |
468 | | // exported this document can't do so again. Throw out |
469 | | // this item in that situation. |
470 | 1.06k | let unique = match dir { |
471 | 705 | Direction::Import => imported_interfaces.insert(id), |
472 | 364 | Direction::Export => exported_interfaces.insert(id), |
473 | | }; |
474 | 1.06k | if !unique { |
475 | 459 | continue; |
476 | 610 | } |
477 | 610 | part.push_str(";"); |
478 | | } |
479 | | ItemKind::AnonInterface(_) => { |
480 | 11.2k | let iface = InterfaceGenerator::new(self.generator, self.file) |
481 | 11.2k | .gen_interface(u, None)?; |
482 | 11.2k | part.push_str(&iface); |
483 | | } |
484 | | |
485 | | ItemKind::Type => { |
486 | 5.02k | let name = name.unwrap(); |
487 | 5.02k | let (ty, typedef) = self.gen_typedef(u, &name)?; |
488 | 5.02k | assert!(part.is_empty()); |
489 | 5.02k | part = typedef; |
490 | 5.02k | let is_resource = ty.is_resource; |
491 | 5.02k | self.types_in_interface.push(ty); |
492 | 5.02k | |
493 | 5.02k | if is_resource { |
494 | 828 | if u.arbitrary()? { |
495 | 772 | part.push_str(" {\n"); |
496 | 772 | self.gen_resource_funcs(u, &mut part)?; |
497 | 772 | part.push_str("}"); |
498 | 56 | } else { |
499 | 56 | part.push_str(";"); |
500 | 56 | } |
501 | 4.19k | } |
502 | | } |
503 | | |
504 | | ItemKind::Use => { |
505 | 7.28k | if !self.gen_use(u, &mut part)? { |
506 | 4.57k | continue; |
507 | 2.71k | } |
508 | | } |
509 | | } |
510 | 21.7k | parts.push(part); |
511 | | } |
512 | | |
513 | 6.95k | shuffle(u, &mut parts)?; |
514 | | |
515 | 28.7k | for part in parts { |
516 | 21.7k | ret.push_str(&part); |
517 | 21.7k | ret.push_str("\n"); |
518 | 21.7k | } |
519 | | |
520 | 6.95k | ret.push_str("}"); |
521 | 6.95k | |
522 | 6.95k | Ok(ret) |
523 | 6.95k | } |
524 | | |
525 | 4.29k | fn gen_resource_funcs(&mut self, u: &mut Unstructured<'_>, ret: &mut String) -> Result<()> { |
526 | 4.29k | let mut parts = Vec::new(); |
527 | | |
528 | 20.3k | #[derive(Arbitrary)] <<wit_smith::generate::InterfaceGenerator>::gen_resource_funcs::Item as arbitrary::Arbitrary>::arbitrary::{closure#0} Line | Count | Source | 528 | 10 | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_resource_funcs::Item as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 528 | 20.3k | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_resource_funcs::Item as arbitrary::Arbitrary>::arbitrary::{closure#2} Line | Count | Source | 528 | 10 | #[derive(Arbitrary)] |
Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_resource_funcs::Item as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_resource_funcs::Item as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_resource_funcs::Item as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_resource_funcs::Item as arbitrary::Arbitrary>::size_hint::{closure#0} |
529 | | enum Item { |
530 | | Constructor, |
531 | | Static, |
532 | | Method, |
533 | | } |
534 | | |
535 | 4.29k | let mut has_constructor = false; |
536 | 4.29k | let mut names = HashSet::new(); |
537 | 24.6k | while parts.len() < self.config.max_resource_items && !u.is_empty() && u.arbitrary()? { |
538 | 20.3k | match u.arbitrary()? { |
539 | 808 | Item::Constructor if has_constructor => {} |
540 | | Item::Constructor => { |
541 | 978 | has_constructor = true; |
542 | 978 | let mut part = format!("constructor"); |
543 | 978 | self.gen_params(u, &mut part, false)?; |
544 | 978 | part.push_str(";"); |
545 | 978 | parts.push(part); |
546 | | } |
547 | | Item::Static => { |
548 | 9.50k | let mut part = format!("%"); |
549 | 9.50k | part.push_str(&gen_unique_name(u, &mut names)?); |
550 | 9.50k | part.push_str(": static "); |
551 | 9.50k | self.gen_func_sig(u, &mut part, false)?; |
552 | 9.50k | parts.push(part); |
553 | | } |
554 | | Item::Method => { |
555 | 9.09k | let mut part = format!("%"); |
556 | 9.09k | part.push_str(&gen_unique_name(u, &mut names)?); |
557 | 9.09k | part.push_str(": "); |
558 | 9.09k | self.gen_func_sig(u, &mut part, true)?; |
559 | 9.09k | parts.push(part); |
560 | | } |
561 | | } |
562 | | } |
563 | | |
564 | 4.29k | shuffle(u, &mut parts)?; |
565 | | |
566 | 23.8k | for part in parts { |
567 | 19.5k | ret.push_str(&part); |
568 | 19.5k | ret.push_str("\n"); |
569 | 19.5k | } |
570 | 4.29k | Ok(()) |
571 | 4.29k | } |
572 | | |
573 | 21.2k | fn gen_use(&mut self, u: &mut Unstructured<'_>, part: &mut String) -> Result<bool> { |
574 | 21.2k | let mut path = String::new(); |
575 | 21.2k | let (_name, _id, types) = match self.generator.gen_path(u, self.file, &mut path)? { |
576 | 10.2k | Some(types) => types, |
577 | 11.0k | None => return Ok(false), |
578 | | }; |
579 | 10.2k | part.push_str("use "); |
580 | 10.2k | part.push_str(&path); |
581 | 10.2k | part.push_str(".{"); |
582 | 10.2k | let ty = u.choose(types)?; |
583 | 10.2k | part.push_str("%"); |
584 | 10.2k | part.push_str(&ty.name); |
585 | 10.2k | let size = ty.size; |
586 | 10.2k | let is_resource = ty.is_resource; |
587 | 10.2k | let name = if self.unique_names.contains(&ty.name) || u.arbitrary()? { |
588 | 9.32k | part.push_str(" as %"); |
589 | 9.32k | let name = self.gen_unique_name(u)?; |
590 | 9.32k | part.push_str(&name); |
591 | 9.32k | name |
592 | | } else { |
593 | 928 | assert!(self.unique_names.insert(ty.name.clone())); |
594 | 928 | ty.name.clone() |
595 | | }; |
596 | 10.2k | self.types_in_interface.push(Type { |
597 | 10.2k | name, |
598 | 10.2k | size, |
599 | 10.2k | is_resource, |
600 | 10.2k | }); |
601 | 10.2k | part.push_str("};"); |
602 | 10.2k | Ok(true) |
603 | 21.2k | } |
604 | | |
605 | 64.6k | fn gen_typedef(&mut self, u: &mut Unstructured<'_>, name: &str) -> Result<(Type, String)> { |
606 | 64.6k | #[derive(Arbitrary)] <<wit_smith::generate::InterfaceGenerator>::gen_typedef::Kind as arbitrary::Arbitrary>::arbitrary::{closure#0} Line | Count | Source | 606 | 44 | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_typedef::Kind as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 606 | 64.6k | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_typedef::Kind as arbitrary::Arbitrary>::arbitrary::{closure#2} Line | Count | Source | 606 | 44 | #[derive(Arbitrary)] |
Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_typedef::Kind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_typedef::Kind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_typedef::Kind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_typedef::Kind as arbitrary::Arbitrary>::size_hint::{closure#0} |
607 | | pub enum Kind { |
608 | | Record, |
609 | | Flags, |
610 | | Variant, |
611 | | Enum, |
612 | | Anonymous, |
613 | | Resource, |
614 | | } |
615 | | |
616 | 64.6k | let mut fuel = self.config.max_type_size; |
617 | 64.6k | let mut ret = String::new(); |
618 | 64.6k | let mut is_resource = false; |
619 | 64.6k | match u.arbitrary()? { |
620 | | Kind::Record => { |
621 | 3.10k | ret.push_str("record %"); |
622 | 3.10k | ret.push_str(name); |
623 | 3.10k | ret.push_str(" {\n"); |
624 | 3.10k | for _ in 0..u.int_in_range(1..=self.config.max_type_parts)? { |
625 | 11.0k | ret.push_str(" %"); |
626 | 11.0k | ret.push_str(&self.gen_unique_name(u)?); |
627 | 11.0k | ret.push_str(": "); |
628 | 11.0k | self.gen_type(u, &mut fuel, &mut ret)?; |
629 | 11.0k | ret.push_str(",\n"); |
630 | | } |
631 | 3.10k | ret.push_str("}"); |
632 | | } |
633 | | Kind::Variant => { |
634 | 2.12k | ret.push_str("variant %"); |
635 | 2.12k | ret.push_str(name); |
636 | 2.12k | ret.push_str(" {\n"); |
637 | 2.12k | for _ in 0..u.int_in_range(1..=self.config.max_type_parts)? { |
638 | 6.89k | ret.push_str(" %"); |
639 | 6.89k | ret.push_str(&self.gen_unique_name(u)?); |
640 | 6.89k | if u.arbitrary()? { |
641 | 5.97k | ret.push_str("("); |
642 | 5.97k | self.gen_type(u, &mut fuel, &mut ret)?; |
643 | 5.97k | ret.push_str(")"); |
644 | 921 | } |
645 | 6.89k | ret.push_str(",\n"); |
646 | | } |
647 | 2.12k | ret.push_str("}"); |
648 | | } |
649 | | Kind::Enum => { |
650 | 50.4k | ret.push_str("enum %"); |
651 | 50.4k | ret.push_str(name); |
652 | 50.4k | ret.push_str(" {\n"); |
653 | 50.4k | for _ in 0..u.int_in_range(1..=self.config.max_type_parts)? { |
654 | 172k | ret.push_str(" %"); |
655 | 172k | ret.push_str(&self.gen_unique_name(u)?); |
656 | 172k | ret.push_str(",\n"); |
657 | | } |
658 | 50.4k | ret.push_str("}"); |
659 | | } |
660 | | Kind::Flags => { |
661 | 1.00k | ret.push_str("flags %"); |
662 | 1.00k | ret.push_str(name); |
663 | 1.00k | ret.push_str(" {\n"); |
664 | 1.00k | for _ in 0..u.int_in_range(1..=self.config.max_type_parts)? { |
665 | 3.36k | ret.push_str(" %"); |
666 | 3.36k | ret.push_str(&self.gen_unique_name(u)?); |
667 | 3.36k | ret.push_str(",\n"); |
668 | | } |
669 | 1.00k | ret.push_str("}"); |
670 | | } |
671 | | Kind::Anonymous => { |
672 | 3.21k | ret.push_str("type %"); |
673 | 3.21k | ret.push_str(name); |
674 | 3.21k | ret.push_str(" = "); |
675 | 3.21k | self.gen_type(u, &mut fuel, &mut ret)?; |
676 | 3.21k | ret.push_str(";"); |
677 | | } |
678 | 4.76k | Kind::Resource => { |
679 | 4.76k | is_resource = true; |
680 | 4.76k | ret.push_str("resource %"); |
681 | 4.76k | ret.push_str(name); |
682 | 4.76k | } |
683 | | } |
684 | | |
685 | 64.6k | let ty = Type { |
686 | 64.6k | size: self.config.max_type_size - fuel, |
687 | 64.6k | is_resource, |
688 | 64.6k | name: name.to_string(), |
689 | 64.6k | }; |
690 | 64.6k | Ok((ty, ret)) |
691 | 64.6k | } |
692 | | |
693 | 291k | fn gen_type( |
694 | 291k | &mut self, |
695 | 291k | u: &mut Unstructured<'_>, |
696 | 291k | fuel: &mut usize, |
697 | 291k | dst: &mut String, |
698 | 291k | ) -> Result<()> { |
699 | 238k | #[derive(Arbitrary)] <<wit_smith::generate::InterfaceGenerator>::gen_type::Kind as arbitrary::Arbitrary>::arbitrary::{closure#0} Line | Count | Source | 699 | 4.29k | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_type::Kind as arbitrary::Arbitrary>::arbitrary::{closure#1} Line | Count | Source | 699 | 234k | #[derive(Arbitrary)] |
<<wit_smith::generate::InterfaceGenerator>::gen_type::Kind as arbitrary::Arbitrary>::arbitrary::{closure#2} Line | Count | Source | 699 | 4.29k | #[derive(Arbitrary)] |
Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_type::Kind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_type::Kind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_type::Kind as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2} Unexecuted instantiation: <<wit_smith::generate::InterfaceGenerator>::gen_type::Kind as arbitrary::Arbitrary>::size_hint::{closure#0} |
700 | | enum Kind { |
701 | | Bool, |
702 | | U8, |
703 | | U16, |
704 | | U32, |
705 | | U64, |
706 | | S8, |
707 | | S16, |
708 | | S32, |
709 | | S64, |
710 | | F32, |
711 | | F64, |
712 | | Char, |
713 | | String, |
714 | | Id, |
715 | | Tuple, |
716 | | Option, |
717 | | Result, |
718 | | List, |
719 | | Stream, |
720 | | Future, |
721 | | ErrorContext, |
722 | | } |
723 | | |
724 | 291k | *fuel = match fuel.checked_sub(1) { |
725 | 228k | Some(fuel) => fuel, |
726 | | None => { |
727 | 62.1k | dst.push_str("bool"); |
728 | 62.1k | return Ok(()); |
729 | | } |
730 | | }; |
731 | | loop { |
732 | 234k | break match u.arbitrary()? { |
733 | 14.9k | Kind::Bool => dst.push_str("bool"), |
734 | 2.78k | Kind::U8 => dst.push_str("u8"), |
735 | 849 | Kind::S8 => dst.push_str("s8"), |
736 | 1.34k | Kind::U16 => dst.push_str("u16"), |
737 | 2.52k | Kind::S16 => dst.push_str("s16"), |
738 | 2.83k | Kind::U32 => dst.push_str("u32"), |
739 | 4.46k | Kind::S32 => dst.push_str("s32"), |
740 | 1.76k | Kind::U64 => dst.push_str("u64"), |
741 | 4.99k | Kind::S64 => dst.push_str("s64"), |
742 | 4.82k | Kind::F32 => dst.push_str("f32"), |
743 | 22.5k | Kind::F64 => dst.push_str("f64"), |
744 | 33.6k | Kind::Char => dst.push_str("char"), |
745 | 1.64k | Kind::String => dst.push_str("string"), |
746 | | Kind::Id => { |
747 | 5.17k | if self.types_in_interface.is_empty() { |
748 | 1.77k | continue; |
749 | 3.40k | } |
750 | 3.40k | let ty = u.choose(&self.types_in_interface)?; |
751 | 3.40k | *fuel = match fuel.checked_sub(ty.size) { |
752 | 3.16k | Some(fuel) => fuel, |
753 | 245 | None => continue, |
754 | | }; |
755 | 3.16k | let own_wrapper = if ty.is_resource && u.arbitrary()? { |
756 | 1.24k | dst.push_str("own<"); |
757 | 1.24k | true |
758 | | } else { |
759 | 1.91k | false |
760 | | }; |
761 | 3.16k | dst.push_str("%"); |
762 | 3.16k | dst.push_str(&ty.name); |
763 | 3.16k | if own_wrapper { |
764 | 1.24k | dst.push_str(">"); |
765 | 1.91k | } |
766 | | } |
767 | | Kind::Tuple => { |
768 | 30.1k | let fields = u.int_in_range(1..=self.config.max_type_parts)?; |
769 | 30.1k | *fuel = match fuel.checked_sub(fields) { |
770 | 27.9k | Some(fuel) => fuel, |
771 | 2.12k | None => continue, |
772 | | }; |
773 | 27.9k | dst.push_str("tuple<"); |
774 | 100k | for i in 0..fields { |
775 | 100k | if i > 0 { |
776 | 72.4k | dst.push_str(", "); |
777 | 72.4k | } |
778 | 100k | self.gen_type(u, fuel, dst)?; |
779 | | } |
780 | 27.9k | dst.push_str(">"); |
781 | | } |
782 | | Kind::Option => { |
783 | 17.2k | *fuel = match fuel.checked_sub(1) { |
784 | 17.1k | Some(fuel) => fuel, |
785 | 132 | None => continue, |
786 | | }; |
787 | 17.1k | dst.push_str("option<"); |
788 | 17.1k | self.gen_type(u, fuel, dst)?; |
789 | 17.1k | dst.push_str(">"); |
790 | | } |
791 | | Kind::List => { |
792 | 4.25k | *fuel = match fuel.checked_sub(1) { |
793 | 4.01k | Some(fuel) => fuel, |
794 | 244 | None => continue, |
795 | | }; |
796 | 4.01k | dst.push_str("list<"); |
797 | 4.01k | self.gen_type(u, fuel, dst)?; |
798 | 4.01k | dst.push_str(">"); |
799 | | } |
800 | | Kind::Result => { |
801 | 7.60k | *fuel = match fuel.checked_sub(2) { |
802 | 6.61k | Some(fuel) => fuel, |
803 | 990 | None => continue, |
804 | | }; |
805 | 6.61k | dst.push_str("result"); |
806 | 6.61k | let ok = u.arbitrary()?; |
807 | 6.61k | let err = u.arbitrary()?; |
808 | 6.61k | match (ok, err) { |
809 | | (true, true) => { |
810 | 4.42k | dst.push_str("<"); |
811 | 4.42k | self.gen_type(u, fuel, dst)?; |
812 | 4.42k | dst.push_str(", "); |
813 | 4.42k | self.gen_type(u, fuel, dst)?; |
814 | 4.42k | dst.push_str(">"); |
815 | | } |
816 | | (true, false) => { |
817 | 614 | dst.push_str("<"); |
818 | 614 | self.gen_type(u, fuel, dst)?; |
819 | 614 | dst.push_str(">"); |
820 | | } |
821 | | (false, true) => { |
822 | 1.39k | dst.push_str("<_, "); |
823 | 1.39k | self.gen_type(u, fuel, dst)?; |
824 | 1.39k | dst.push_str(">"); |
825 | | } |
826 | 176 | (false, false) => {} |
827 | | } |
828 | | } |
829 | | Kind::Stream => { |
830 | 6.22k | *fuel = match fuel.checked_sub(1) { |
831 | 6.18k | Some(fuel) => fuel, |
832 | 47 | None => continue, |
833 | | }; |
834 | 6.18k | dst.push_str("stream<"); |
835 | 6.18k | self.gen_type(u, fuel, dst)?; |
836 | 6.18k | dst.push_str(">"); |
837 | | } |
838 | | Kind::Future => { |
839 | 22.4k | *fuel = match fuel.checked_sub(1) { |
840 | 22.3k | Some(fuel) => fuel, |
841 | 35 | None => continue, |
842 | | }; |
843 | 22.3k | if u.arbitrary()? { |
844 | 21.3k | dst.push_str("future<"); |
845 | 21.3k | self.gen_type(u, fuel, dst)?; |
846 | 21.3k | dst.push_str(">"); |
847 | 1.01k | } else { |
848 | 1.01k | dst.push_str("future"); |
849 | 1.01k | } |
850 | | } |
851 | 42.1k | Kind::ErrorContext => { |
852 | 42.1k | dst.push_str("error-context"); |
853 | 42.1k | } |
854 | | }; |
855 | | } |
856 | | |
857 | 228k | Ok(()) |
858 | 291k | } |
859 | | |
860 | 16.5k | fn gen_func(&mut self, u: &mut Unstructured<'_>) -> Result<String> { |
861 | 16.5k | let mut ret = "%".to_string(); |
862 | 16.5k | ret.push_str(&self.gen_unique_name(u)?); |
863 | 16.5k | ret.push_str(": "); |
864 | 16.5k | self.gen_func_sig(u, &mut ret, false)?; |
865 | 16.5k | Ok(ret) |
866 | 16.5k | } |
867 | | |
868 | 37.2k | fn gen_func_sig( |
869 | 37.2k | &mut self, |
870 | 37.2k | u: &mut Unstructured<'_>, |
871 | 37.2k | dst: &mut String, |
872 | 37.2k | method: bool, |
873 | 37.2k | ) -> Result<()> { |
874 | 37.2k | dst.push_str("func"); |
875 | 37.2k | self.gen_params(u, dst, method)?; |
876 | 37.2k | if u.arbitrary()? { |
877 | 32.8k | dst.push_str(" -> "); |
878 | 32.8k | let mut fuel = self.config.max_type_size; |
879 | 32.8k | self.gen_type(u, &mut fuel, dst)?; |
880 | 4.40k | } |
881 | 37.2k | dst.push_str(";"); |
882 | 37.2k | Ok(()) |
883 | 37.2k | } |
884 | | |
885 | 38.2k | fn gen_params( |
886 | 38.2k | &mut self, |
887 | 38.2k | u: &mut Unstructured<'_>, |
888 | 38.2k | dst: &mut String, |
889 | 38.2k | method: bool, |
890 | 38.2k | ) -> Result<()> { |
891 | 38.2k | dst.push_str("("); |
892 | 38.2k | let mut names = HashSet::new(); |
893 | 38.2k | if method { |
894 | 9.09k | names.insert("self".to_string()); |
895 | 29.1k | } |
896 | 38.2k | let mut fuel = self.config.max_type_size; |
897 | 77.8k | for i in 0..u.int_in_range(0..=self.config.max_type_parts)? { |
898 | 77.8k | if i > 0 { |
899 | 42.9k | dst.push_str(", "); |
900 | 42.9k | } |
901 | 77.8k | dst.push_str("%"); |
902 | 77.8k | dst.push_str(&gen_unique_name(u, &mut names)?); |
903 | 77.8k | dst.push_str(": "); |
904 | 77.8k | self.gen_type(u, &mut fuel, dst)?; |
905 | | } |
906 | 38.2k | dst.push_str(")"); |
907 | 38.2k | Ok(()) |
908 | 38.2k | } |
909 | | |
910 | 279k | fn gen_unique_name(&mut self, u: &mut Unstructured<'_>) -> Result<String> { |
911 | 279k | gen_unique_name(u, &mut self.unique_names) |
912 | 279k | } |
913 | | } |
914 | | |
915 | 401k | fn gen_unique_name(u: &mut Unstructured<'_>, set: &mut HashSet<String>) -> Result<String> { |
916 | 401k | let mut name = gen_name(u)?; |
917 | 714k | while !set.insert(name.clone()) { |
918 | 313k | write!(&mut name, "{}", set.len()).unwrap(); |
919 | 313k | } |
920 | 401k | Ok(name) |
921 | 401k | } |
922 | | |
923 | 423k | fn gen_name(u: &mut Unstructured<'_>) -> Result<String> { |
924 | 423k | let size = u.arbitrary_len::<u8>()?; |
925 | 423k | let size = std::cmp::min(size, 20); |
926 | 423k | let name = match str::from_utf8(u.peek_bytes(size).unwrap()) { |
927 | 49.1k | Ok(s) => { |
928 | 49.1k | u.bytes(size).unwrap(); |
929 | 49.1k | s.to_string() |
930 | | } |
931 | 374k | Err(e) => { |
932 | 374k | let i = e.valid_up_to(); |
933 | 374k | let valid = u.bytes(i).unwrap(); |
934 | 374k | str::from_utf8(valid).unwrap().to_string() |
935 | | } |
936 | | }; |
937 | 423k | let name = name |
938 | 423k | .chars() |
939 | 423k | .map(|x| if x.is_ascii_lowercase() { x } else { 'x' }) |
940 | 423k | .collect::<String>(); |
941 | 423k | Ok(if name.is_empty() { |
942 | 380k | "name".to_string() |
943 | | } else { |
944 | 42.9k | name |
945 | | }) |
946 | 423k | } |
947 | | |
948 | 49.9k | fn shuffle<T>(u: &mut Unstructured<'_>, mut slice: &mut [T]) -> Result<()> { |
949 | 206k | while slice.len() > 0 { |
950 | 156k | let pos = u.int_in_range(0..=slice.len() - 1)?; |
951 | 156k | slice.swap(0, pos); |
952 | 156k | slice = &mut slice[1..]; |
953 | | } |
954 | 49.9k | Ok(()) |
955 | 49.9k | } wit_smith::generate::shuffle::<wit_smith::generate::File> Line | Count | Source | 948 | 3.56k | fn shuffle<T>(u: &mut Unstructured<'_>, mut slice: &mut [T]) -> Result<()> { | 949 | 12.7k | while slice.len() > 0 { | 950 | 9.18k | let pos = u.int_in_range(0..=slice.len() - 1)?; | 951 | 9.18k | slice.swap(0, pos); | 952 | 9.18k | slice = &mut slice[1..]; | 953 | | } | 954 | 3.56k | Ok(()) | 955 | 3.56k | } |
wit_smith::generate::shuffle::<alloc::string::String> Line | Count | Source | 948 | 46.4k | fn shuffle<T>(u: &mut Unstructured<'_>, mut slice: &mut [T]) -> Result<()> { | 949 | 194k | while slice.len() > 0 { | 950 | 147k | let pos = u.int_in_range(0..=slice.len() - 1)?; | 951 | 147k | slice.swap(0, pos); | 952 | 147k | slice = &mut slice[1..]; | 953 | | } | 954 | 46.4k | Ok(()) | 955 | 46.4k | } |
|
956 | | |
957 | | #[derive(Default)] |
958 | | struct File { |
959 | | items: Vec<String>, |
960 | | namespace: HashMap<String, Definition>, |
961 | | interfaces: IndexMap<String, FileInterface>, |
962 | | } |
963 | | |
964 | | #[derive(Clone)] |
965 | | struct FileInterface { |
966 | | name: String, |
967 | | id: u32, |
968 | | types: Rc<TypeList>, |
969 | | } |
970 | | |
971 | | #[derive(PartialEq)] |
972 | | enum Definition { |
973 | | Package, |
974 | | File, |
975 | | } |
976 | | |
977 | | impl File { |
978 | 21.6k | fn gen_unique_package_name( |
979 | 21.6k | &mut self, |
980 | 21.6k | u: &mut Unstructured<'_>, |
981 | 21.6k | names: &mut HashSet<String>, |
982 | 21.6k | ) -> Result<String> { |
983 | 21.6k | let mut name = gen_name(u)?; |
984 | | loop { |
985 | | // Find a package-unique name first |
986 | 36.3k | if !names.insert(name.clone()) { |
987 | 14.6k | write!(&mut name, "{}", names.len()).unwrap(); |
988 | 14.6k | continue; |
989 | 21.7k | } |
990 | 21.7k | |
991 | 21.7k | // Then make sure it's file-unique too |
992 | 21.7k | if self.claim_file_name(&mut name) { |
993 | 21.6k | break; |
994 | 10 | } |
995 | | } |
996 | 21.6k | Ok(name) |
997 | 21.6k | } |
998 | | |
999 | 769 | fn gen_unique_file_name(&mut self, u: &mut Unstructured<'_>) -> Result<String> { |
1000 | 769 | let mut name = gen_name(u)?; |
1001 | 889 | while !self.claim_file_name(&mut name) { |
1002 | 120 | // try again on the next iteration |
1003 | 120 | } |
1004 | 769 | Ok(name) |
1005 | 769 | } |
1006 | | |
1007 | 22.5k | fn claim_file_name(&mut self, name: &mut String) -> bool { |
1008 | 22.5k | match self.namespace.entry(name.clone()) { |
1009 | 215 | Entry::Occupied(mut e) => match e.get() { |
1010 | | // If this name is already claimed elsewhere in the package |
1011 | | // then that's ok as we're going to shadow it, so switch it |
1012 | | // to a file definition. |
1013 | 85 | Definition::Package => *e.get_mut() = Definition::File, |
1014 | | |
1015 | | // If it's already defined in the file try to add more stuff |
1016 | | // to the name to make the next try not collide. |
1017 | | Definition::File => { |
1018 | 130 | name.push_str("y"); |
1019 | 130 | write!(name, "{}", self.namespace.len()).unwrap(); |
1020 | 130 | return false; |
1021 | | } |
1022 | | }, |
1023 | | |
1024 | | // Not defined? Claim it. |
1025 | 22.3k | Entry::Vacant(v) => { |
1026 | 22.3k | v.insert(Definition::File); |
1027 | 22.3k | } |
1028 | | } |
1029 | 22.4k | true |
1030 | 22.5k | } |
1031 | | |
1032 | 7.82k | fn insert_definition(&mut self, def: FileInterface) { |
1033 | 7.82k | match self.namespace.get(&def.name) { |
1034 | 3.32k | Some(Definition::File) => return, |
1035 | 0 | Some(Definition::Package) => unreachable!(), |
1036 | 4.50k | None => {} |
1037 | 4.50k | } |
1038 | 4.50k | let prev = self.namespace.insert(def.name.clone(), Definition::Package); |
1039 | 4.50k | assert!(prev.is_none()); |
1040 | 4.50k | let prev = self.interfaces.insert(def.name.clone(), def); |
1041 | 4.50k | assert!(prev.is_none()); |
1042 | 7.82k | } |
1043 | | } |
1044 | | |
1045 | 2.78k | fn gen_version(u: &mut Unstructured<'_>) -> Result<Version> { |
1046 | 2.78k | Ok(Version { |
1047 | 2.78k | major: u.int_in_range(0..=10)?, |
1048 | 2.78k | minor: u.int_in_range(0..=10)?, |
1049 | 2.78k | patch: u.int_in_range(0..=10)?, |
1050 | 2.78k | pre: if u.arbitrary()? { |
1051 | 2.09k | semver::Prerelease::new("alpha.0").unwrap() |
1052 | | } else { |
1053 | 693 | semver::Prerelease::EMPTY |
1054 | | }, |
1055 | 2.78k | build: if u.arbitrary()? { |
1056 | 1.94k | semver::BuildMetadata::new("1.2.0").unwrap() |
1057 | | } else { |
1058 | 848 | semver::BuildMetadata::EMPTY |
1059 | | }, |
1060 | | }) |
1061 | 2.78k | } |