├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── my_benchmark.rs ├── src ├── bin │ ├── arguments.rs │ ├── buffer.rs │ ├── main.rs │ ├── man.rs │ └── mod.rs ├── index_counters.rs ├── lib.rs ├── list_wrapper.rs └── list_wrapper │ ├── single_list.rs │ ├── tuple_of_lists.rs │ └── vec_of_lists.rs └── tests ├── million_permutations.rs ├── permutation_values.rs ├── reset.rs ├── single_list_permutation.rs ├── todo.rs └── tuples.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "arrayvec" 5 | version = "0.4.10" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "atty" 13 | version = "0.2.11" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 18 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 19 | ] 20 | 21 | [[package]] 22 | name = "bitflags" 23 | version = "1.0.4" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | 26 | [[package]] 27 | name = "byteorder" 28 | version = "1.3.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | 31 | [[package]] 32 | name = "cast" 33 | version = "0.2.2" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | 36 | [[package]] 37 | name = "cfg-if" 38 | version = "0.1.7" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | 41 | [[package]] 42 | name = "clap" 43 | version = "2.33.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | dependencies = [ 46 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 47 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 48 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 49 | ] 50 | 51 | [[package]] 52 | name = "cloudabi" 53 | version = "0.0.3" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | dependencies = [ 56 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 57 | ] 58 | 59 | [[package]] 60 | name = "criterion" 61 | version = "0.2.11" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | dependencies = [ 64 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 66 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 68 | "csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 69 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 70 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 71 | "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", 72 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 73 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 74 | "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 75 | "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 76 | "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 77 | "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 78 | "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 79 | "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 80 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 81 | "tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 82 | "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 83 | ] 84 | 85 | [[package]] 86 | name = "criterion-plot" 87 | version = "0.3.1" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | dependencies = [ 90 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 91 | "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 92 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 93 | ] 94 | 95 | [[package]] 96 | name = "crossbeam-deque" 97 | version = "0.2.0" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | dependencies = [ 100 | "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 101 | "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 102 | ] 103 | 104 | [[package]] 105 | name = "crossbeam-epoch" 106 | version = "0.3.1" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | dependencies = [ 109 | "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 110 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 111 | "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 112 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 113 | "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 114 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 115 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 116 | ] 117 | 118 | [[package]] 119 | name = "crossbeam-utils" 120 | version = "0.2.2" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | dependencies = [ 123 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 124 | ] 125 | 126 | [[package]] 127 | name = "csv" 128 | version = "1.0.7" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | dependencies = [ 131 | "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 132 | "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 133 | "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 134 | "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 135 | ] 136 | 137 | [[package]] 138 | name = "csv-core" 139 | version = "0.1.5" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | dependencies = [ 142 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 143 | ] 144 | 145 | [[package]] 146 | name = "either" 147 | version = "1.5.2" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | 150 | [[package]] 151 | name = "fuchsia-cprng" 152 | version = "0.1.1" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | 155 | [[package]] 156 | name = "itertools" 157 | version = "0.8.0" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | dependencies = [ 160 | "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 161 | ] 162 | 163 | [[package]] 164 | name = "itoa" 165 | version = "0.4.3" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | 168 | [[package]] 169 | name = "lazy_static" 170 | version = "1.3.0" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | 173 | [[package]] 174 | name = "libc" 175 | version = "0.2.53" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | 178 | [[package]] 179 | name = "memchr" 180 | version = "2.2.0" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | dependencies = [ 183 | "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", 184 | ] 185 | 186 | [[package]] 187 | name = "memoffset" 188 | version = "0.2.1" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | 191 | [[package]] 192 | name = "nodrop" 193 | version = "0.1.13" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | 196 | [[package]] 197 | name = "num-traits" 198 | version = "0.2.6" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | 201 | [[package]] 202 | name = "num_cpus" 203 | version = "1.10.0" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | dependencies = [ 206 | "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", 207 | ] 208 | 209 | [[package]] 210 | name = "numtoa" 211 | version = "0.1.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | 214 | [[package]] 215 | name = "permutate" 216 | version = "0.3.2" 217 | dependencies = [ 218 | "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 219 | ] 220 | 221 | [[package]] 222 | name = "proc-macro2" 223 | version = "0.4.29" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | dependencies = [ 226 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 227 | ] 228 | 229 | [[package]] 230 | name = "quote" 231 | version = "0.6.12" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | dependencies = [ 234 | "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)", 235 | ] 236 | 237 | [[package]] 238 | name = "rand_core" 239 | version = "0.3.1" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | dependencies = [ 242 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 243 | ] 244 | 245 | [[package]] 246 | name = "rand_core" 247 | version = "0.4.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | 250 | [[package]] 251 | name = "rand_os" 252 | version = "0.1.3" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | dependencies = [ 255 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 256 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 257 | "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", 258 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 259 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 260 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 261 | ] 262 | 263 | [[package]] 264 | name = "rand_xoshiro" 265 | version = "0.1.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | dependencies = [ 268 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 269 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 270 | ] 271 | 272 | [[package]] 273 | name = "rayon" 274 | version = "1.0.3" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | dependencies = [ 277 | "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 278 | "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 279 | "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 280 | ] 281 | 282 | [[package]] 283 | name = "rayon-core" 284 | version = "1.4.1" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | dependencies = [ 287 | "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 288 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 289 | "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", 290 | "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 291 | ] 292 | 293 | [[package]] 294 | name = "rdrand" 295 | version = "0.4.0" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | dependencies = [ 298 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 299 | ] 300 | 301 | [[package]] 302 | name = "redox_syscall" 303 | version = "0.1.54" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | 306 | [[package]] 307 | name = "redox_termios" 308 | version = "0.1.1" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | dependencies = [ 311 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 312 | ] 313 | 314 | [[package]] 315 | name = "ryu" 316 | version = "0.2.7" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | 319 | [[package]] 320 | name = "same-file" 321 | version = "1.0.4" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | dependencies = [ 324 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 325 | ] 326 | 327 | [[package]] 328 | name = "scopeguard" 329 | version = "0.3.3" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | 332 | [[package]] 333 | name = "serde" 334 | version = "1.0.90" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | 337 | [[package]] 338 | name = "serde_derive" 339 | version = "1.0.90" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | dependencies = [ 342 | "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)", 343 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 344 | "syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)", 345 | ] 346 | 347 | [[package]] 348 | name = "serde_json" 349 | version = "1.0.39" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | dependencies = [ 352 | "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 353 | "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 354 | "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 355 | ] 356 | 357 | [[package]] 358 | name = "syn" 359 | version = "0.15.33" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | dependencies = [ 362 | "proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)", 363 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 364 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 365 | ] 366 | 367 | [[package]] 368 | name = "termion" 369 | version = "1.5.2" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | dependencies = [ 372 | "libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)", 373 | "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 374 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 375 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 376 | ] 377 | 378 | [[package]] 379 | name = "textwrap" 380 | version = "0.11.0" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | dependencies = [ 383 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 384 | ] 385 | 386 | [[package]] 387 | name = "tinytemplate" 388 | version = "1.0.1" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | dependencies = [ 391 | "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", 392 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 393 | ] 394 | 395 | [[package]] 396 | name = "unicode-width" 397 | version = "0.1.5" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | 400 | [[package]] 401 | name = "unicode-xid" 402 | version = "0.1.0" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | 405 | [[package]] 406 | name = "walkdir" 407 | version = "2.2.7" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | dependencies = [ 410 | "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 411 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 412 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 413 | ] 414 | 415 | [[package]] 416 | name = "winapi" 417 | version = "0.3.7" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | dependencies = [ 420 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 421 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 422 | ] 423 | 424 | [[package]] 425 | name = "winapi-i686-pc-windows-gnu" 426 | version = "0.4.0" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | 429 | [[package]] 430 | name = "winapi-util" 431 | version = "0.1.2" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | dependencies = [ 434 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 435 | ] 436 | 437 | [[package]] 438 | name = "winapi-x86_64-pc-windows-gnu" 439 | version = "0.4.0" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | 442 | [metadata] 443 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" 444 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 445 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 446 | "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" 447 | "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" 448 | "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" 449 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 450 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 451 | "checksum criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0363053954f3e679645fc443321ca128b7b950a6fe288cf5f9335cc22ee58394" 452 | "checksum criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76f9212ddf2f4a9eb2d401635190600656a1f88a932ef53d06e7fa4c7e02fb8e" 453 | "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" 454 | "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" 455 | "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" 456 | "checksum csv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9044e25afb0924b5a5fc5511689b0918629e85d68ea591e5e87fbf1e85ea1b3b" 457 | "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" 458 | "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" 459 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 460 | "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" 461 | "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 462 | "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" 463 | "checksum libc 0.2.53 (registry+https://github.com/rust-lang/crates.io-index)" = "ec350a9417dfd244dc9a6c4a71e13895a4db6b92f0b106f07ebbc3f3bc580cee" 464 | "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" 465 | "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 466 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 467 | "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 468 | "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" 469 | "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" 470 | "checksum proc-macro2 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)" = "64c827cea7a7ab30ce4593e5e04d7a11617ad6ece2fa230605a78b00ff965316" 471 | "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" 472 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 473 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" 474 | "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 475 | "checksum rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03b418169fb9c46533f326efd6eed2576699c44ca92d3052a066214a8d828929" 476 | "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" 477 | "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" 478 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 479 | "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" 480 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 481 | "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" 482 | "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" 483 | "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 484 | "checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" 485 | "checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" 486 | "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" 487 | "checksum syn 0.15.33 (registry+https://github.com/rust-lang/crates.io-index)" = "ec52cd796e5f01d0067225a5392e70084acc4c0013fa71d55166d38a8b307836" 488 | "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" 489 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 490 | "checksum tinytemplate 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7655088894274afb52b807bd3c87072daa1fedd155068b8705cabfd628956115" 491 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 492 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 493 | "checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" 494 | "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" 495 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 496 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" 497 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 498 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "permutate" 3 | version = "0.3.2" 4 | authors = ["Michael Aaron Murphy "] 5 | license = "MIT" 6 | description = "Generic permutator that permutates singular and multiple lists" 7 | repository = "https://github.com/mmstick/permutate" 8 | documentation = "https://docs.rs/permutate/0.1.0/permutate/" 9 | keywords = ["permutate", "permutator"] 10 | readme = "README.md" 11 | 12 | [features] 13 | # if set then the binary utilities are included 14 | bin-utils = [] 15 | default = ["bin-utils"] 16 | 17 | [[bin]] 18 | name = "permutate-bin" 19 | path = "src/bin/main.rs" 20 | doc = false 21 | required-features = ["bin-utils"] 22 | 23 | [[bench]] 24 | name = "my_benchmark" 25 | harness = false 26 | required-features = ["bin-utils"] 27 | 28 | [dev-dependencies] 29 | criterion = "0.2" 30 | 31 | [profile.release] 32 | lto = true 33 | opt-level = 3 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Michael Aaron Murphy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Permutate 2 | 3 | Permutate exists as both a library and application for permutating 4 | generic vectors or tuples of lists, as well as individual lists, 5 | using an original Rust-based algorithm. 6 | It has been developed primarily for the goal of inclusion within the 7 | Rust implementation of the GNU Parallel program, and brace expansions 8 | within Redox's Ion shell. 9 | 10 | The source code documentation may be found on 11 | [Docs.rs](https://docs.rs/permutate/). 12 | 13 | ## Features 14 | 15 | - `bin-utils` - if set then the binary utilities are included. 16 | - Set by default and is required by the `bin` and `bench` profiles. 17 | 18 | ## Mechanics 19 | 20 | Permutations work by incrementing a vector of index counters, 21 | and returning a vector of references to the underlying data 22 | (unless the container owns the values and they are Copy). 23 | For optimal usage, it is best to perform one iteration with the 24 | `next()` method, and follow up successive iterations with the 25 | `next_with_buffer()` method, so that you can re-use the previous 26 | vector allocation. 27 | It is also possible to obtain the state of the internal index counters 28 | by using the `get_indexes()` method, and set the state with the 29 | `set_indexes` method. 30 | 31 | ## Examples 32 | 33 | These are a list of examples on how to use the library to manipulate 34 | various types of data. 35 | The only thing we may need to ensure is that our list of strings is in the `Vec<&[&str]>` format. 36 | 37 | ### An individual list: [&[&str]; 1] 38 | 39 | ```rust 40 | extern crate permutate; 41 | use permutate::{Permutator, PermutatorWrapper as _, Repeated}; 42 | use std::io::{self, Write}; 43 | 44 | fn main() { 45 | let list: &[&str] = &["one", "two", "three", "four"]; 46 | let list = [list]; 47 | let mut permutator = Permutator::, _>::new(&list); 48 | 49 | // iteration 1: re-utilizes the permutation buffer 50 | // you may opt to re-utilize or not (see iteration 2) 51 | if let Some(mut permutation) = permutator.next() { 52 | // prints each element 53 | for element in &permutation { 54 | println!("{:?}", &element); 55 | } 56 | // re-utilizes the permutation buffer 57 | while let Some(permutation) = permutator.next_with_buffer(&mut permutation) { 58 | // prints each element 59 | for element in permutation { 60 | println!("{:?}", &element); 61 | } 62 | } 63 | } 64 | } 65 | ``` 66 | 67 | ### A vec of slices: `Vec<&[&str]>` 68 | 69 | ```rust 70 | extern crate permutate; 71 | use permutate::{Permutator, PermutatorWrapper as _}; 72 | use std::io::{self, Write}; 73 | 74 | fn main() { 75 | let lists = [ 76 | &["one", "two", "three"][..], 77 | &["four", "five", "six"][..], 78 | &["seven", "eight", "nine"][..], 79 | ]; 80 | let mut permutator = Permutator::new(&lists.to_vec()); 81 | 82 | // iteration 2: allocates a new buffer for each permutation 83 | // you may opt to re-allocate or not (see iteration 1) 84 | for permutation in permutator { 85 | println!("{:?}", &permutation); 86 | } 87 | } 88 | ``` 89 | 90 | ### A Vector of Vector of Strings: `Vec>` 91 | 92 | This is the most complicated example to accomplish because 93 | you have to convert, essentially, a vector of a vector of vectors into 94 | a slice of a slice of a slice, 95 | as the String type itself is a vector of characters. 96 | 97 | ```rust 98 | extern crate permutate; 99 | use permutate::{Permutator, PermutatorWrapper as _}; 100 | use std::io::{self, Write}; 101 | 102 | fn main() { 103 | let lists: Vec> = vec![ 104 | vec!["one".to_owned(), "two".to_owned(), "three".to_owned()], 105 | vec!["four".to_owned(), "five".to_owned(), "six".to_owned()], 106 | vec!["seven".to_owned(), "eight".to_owned(), "nine".to_owned()], 107 | ]; 108 | 109 | // Convert the `Vec>` into a `Vec>` 110 | let tmp: Vec> = lists.iter() 111 | .map(|list| list.iter() 112 | .map(AsRef::as_ref) 113 | .collect::>() 114 | ) 115 | .collect(); 116 | 117 | // Convert the `Vec>` into a `Vec<&[&str]>` 118 | let vector_of_slices: Vec<&[&str]> = tmp.iter() 119 | .map(AsRef::as_ref).collect(); 120 | 121 | // Initialize the Permutator 122 | let mut permutator = Permutator::new(&vector_of_slices); 123 | 124 | // iteration 2: allocates a new buffer for each permutation 125 | // you may opt to re-allocate or not (see iteration 1) 126 | for permutation in permutator { 127 | println!("{:?}", &permutation); 128 | } 129 | } 130 | ``` 131 | 132 | ### A tuple of slices: `(&[&str], &[bool])` 133 | 134 | ```rust 135 | extern crate permutate; 136 | use permutate::{Permutator, PermutatorWrapper as _}; 137 | use std::io::{self, Write}; 138 | 139 | fn main() { 140 | let lists = ( 141 | &["one", "two", "three"][..], 142 | &[false, true][..], 143 | ); 144 | let mut permutator = Permutator::new(&lists); 145 | 146 | // iteration 2: allocates a new buffer for each permutation 147 | // you may opt to re-allocate or not (see iteration 1) 148 | for permutation in permutator { 149 | let (s, b): (&str, bool) = permutation; 150 | println!("{:?}", &(s, b)); 151 | } 152 | } 153 | ``` 154 | Note that the slice of booleans actually owns the booleans, 155 | and so they are `copy`ed at each permutation. 156 | 157 | ## Application 158 | 159 | Following the spirit of the Rust and UNIX philosophy, 160 | I am also releasing this as it's own simple application to bring the 161 | capabilities of the permutate to the command-line, because shell lives 162 | matter. 163 | The syntax is very much identical to GNU Parallel, 164 | so users of GNU Parallel will be right at home with this command. 165 | 166 | ```sh 167 | $ permutate A B ::: C D ::: E F 168 | A C E 169 | A C F 170 | A D E 171 | A D F 172 | B C E 173 | B C F 174 | B D E 175 | B D F 176 | ``` 177 | 178 | ```sh 179 | $ permutate -n A B ::: C D ::: E F 180 | ACE 181 | ACF 182 | ADE 183 | ADF 184 | BCE 185 | BCF 186 | BDE 187 | BDF 188 | ``` 189 | 190 | Other accepted syntaxes are: 191 | 192 | ```sh 193 | $ permutate -f file file :::+ arg arg :::: file file ::::+ file file ::: arg arg 194 | 195 | ``` 196 | 197 | ### Benchmark 198 | 199 | So how fast is it? 200 | try running `cargo bench` to see how fast it creates 10k permutations 201 | over string references, repeated over 10k iterations. 202 | It takes ~550us per iteration on my laptop 203 | (i7-4710HQ Quad Core capped at 1600MHz on ArchLinux), 204 | ie. around 18M permutations per second 205 | (= 10k[permutations/iteration] * 10k[iterations] / 5.50[seconds]). 206 | 207 | Another way of benchmarking it is to use the generated binary directly: 208 | ```sh 209 | $ cargo build --release 210 | $ for char in A B C D E F G H I J; do echo $char >> A; done 211 | $ time target/release/permutate --benchmark -n -f A :::: A :::: A :::: A :::: A :::: A :::: A :::: A 212 | $ rm A 213 | ``` 214 | This will also test for 100M permutations (10^8 permutations), 215 | then you only need to divide 100,000,000 by the duration. 216 | -------------------------------------------------------------------------------- /benches/my_benchmark.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate criterion; 3 | 4 | extern crate permutate; 5 | 6 | use criterion::Criterion; 7 | use permutate::{bin, Permutator, PermutatorWrapper as _}; 8 | 9 | fn get_input<'a>() -> [&'a [&'a str]; 4] { 10 | [ 11 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 10 12 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 100 13 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 1k 14 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 10k 15 | ] 16 | } 17 | 18 | // Executes the same function as the binary, for 10,000 permutations. 19 | fn bin_like_input() { 20 | let input: Vec> = get_input() 21 | .into_iter() 22 | .map(|v| v.into_iter().cloned().map(String::from).collect()) 23 | .collect(); 24 | let (benchmark, _no_delimiters) = (true, false); 25 | bin::prepare(input, benchmark, _no_delimiters); 26 | } 27 | 28 | // Check to see if exactly 10,000 permutations were collected. 29 | fn test_10k_permutations() { 30 | let input: Vec<&[&str]> = get_input().to_vec(); 31 | assert_eq!(10_000, Permutator::new(&input).count()) 32 | } 33 | 34 | fn criterion_benchmark(c: &mut Criterion) { 35 | c.bench_function("perm 10k", |b| b.iter(|| test_10k_permutations())); 36 | c.bench_function("bin-like 10k", |b| b.iter(|| bin_like_input())); 37 | } 38 | 39 | criterion_group!(benches, criterion_benchmark); 40 | criterion_main!(benches); 41 | -------------------------------------------------------------------------------- /src/bin/arguments.rs: -------------------------------------------------------------------------------- 1 | use super::man; 2 | use std::env::args; 3 | use std::fs; 4 | use std::io::{BufRead, BufReader}; 5 | use std::process::exit; 6 | 7 | #[derive(Debug)] 8 | pub enum InputError { 9 | FileError(String, String), 10 | NoInputsProvided, 11 | NotEnoughInputs, 12 | } 13 | 14 | /// Scans input arguments for flags that control the behaviour of the program. 15 | pub fn parse_options() -> (Vec, bool, bool, bool) { 16 | let mut input = Vec::new(); 17 | let (mut benchmark, mut interpret_files, mut no_delimiters) = (false, false, false); 18 | for argument in args().skip(1) { 19 | match argument.as_str() { 20 | "-b" | "--benchmark" => benchmark = true, 21 | "-f" | "--files" => interpret_files = true, 22 | "-h" | "--help" => { 23 | println!("{}", man::MANPAGE); 24 | exit(0); 25 | } 26 | "-n" | "--no-delimiters" => no_delimiters = true, 27 | _ => input.push(argument), 28 | } 29 | } 30 | (input, benchmark, interpret_files, no_delimiters) 31 | } 32 | 33 | /// This is effectively a command-line interpreter designed specifically for this program. 34 | pub fn parse_arguments( 35 | list_collection: &mut Vec>, 36 | input: &str, 37 | interpret_files: bool, 38 | ) -> Result<(), InputError> { 39 | let mut add_to_previous_list = false; 40 | let mut backslash = false; 41 | let mut double_quote = false; 42 | let mut single_quote = false; 43 | let mut match_set = false; 44 | let mut interpret_files = interpret_files; 45 | let mut matches = 0; 46 | let mut current_list = Vec::new(); 47 | let mut current_argument = String::new(); 48 | 49 | for character in input.chars() { 50 | if match_set { 51 | match character { 52 | '+' => add_to_previous_list = true, 53 | ' ' => { 54 | if matches == 3 { 55 | if add_to_previous_list { 56 | add_to_previous_list = false; 57 | } else { 58 | if current_list.is_empty() { 59 | return Err(InputError::NoInputsProvided); 60 | } else { 61 | list_collection.push(current_list.clone()); 62 | current_list.clear(); 63 | } 64 | } 65 | interpret_files = false; 66 | } else if matches == 4 { 67 | if add_to_previous_list { 68 | add_to_previous_list = false; 69 | } else { 70 | if current_list.is_empty() { 71 | return Err(InputError::NoInputsProvided); 72 | } else { 73 | list_collection.push(current_list.clone()); 74 | current_list.clear(); 75 | } 76 | } 77 | interpret_files = true; 78 | } else { 79 | for _ in 0..matches { 80 | current_argument.push(':'); 81 | } 82 | current_list.push(current_argument.clone()); 83 | current_argument.clear(); 84 | } 85 | match_set = false; 86 | matches = 0; 87 | } 88 | ':' if !add_to_previous_list => matches += 1, 89 | _ => { 90 | for _ in 0..matches { 91 | current_argument.push(':'); 92 | } 93 | current_argument.push(character); 94 | match_set = false; 95 | matches = 0; 96 | } 97 | } 98 | } else if backslash { 99 | match character { 100 | '\\' | '\'' | ' ' | '\"' => current_argument.push(character), 101 | _ => { 102 | current_argument.push('\\'); 103 | current_argument.push(' '); 104 | } 105 | } 106 | backslash = false; 107 | } else if single_quote { 108 | match character { 109 | '\\' => backslash = true, 110 | '\'' => single_quote = false, 111 | _ => current_argument.push(character), 112 | } 113 | } else if double_quote { 114 | match character { 115 | '\\' => backslash = true, 116 | '\"' => double_quote = false, 117 | _ => current_argument.push(character), 118 | } 119 | } else { 120 | match character { 121 | ' ' => { 122 | if !current_argument.is_empty() { 123 | if interpret_files { 124 | for argument in try!(file_parse(¤t_argument)) { 125 | current_list.push(argument); 126 | } 127 | } else { 128 | current_list.push(current_argument.clone()); 129 | } 130 | current_argument.clear(); 131 | } 132 | } 133 | '\\' => backslash = true, 134 | '\'' => single_quote = true, 135 | '\"' => double_quote = true, 136 | ':' => { 137 | match_set = true; 138 | matches = 1; 139 | } 140 | _ => current_argument.push(character), 141 | } 142 | } 143 | } 144 | 145 | if !current_argument.is_empty() { 146 | if interpret_files { 147 | for argument in try!(file_parse(¤t_argument)) { 148 | current_list.push(argument); 149 | } 150 | } else { 151 | current_list.push(current_argument); 152 | } 153 | } 154 | 155 | if !current_list.is_empty() { 156 | list_collection.push(current_list); 157 | } 158 | 159 | if list_collection.len() == 0 || (list_collection.len() == 1 && list_collection[0].len() == 1) { 160 | return Err(InputError::NotEnoughInputs); 161 | } else { 162 | Ok(()) 163 | } 164 | } 165 | 166 | /// Attempts to open an input argument and adds each line to the `inputs` list. 167 | fn file_parse(path: &str) -> Result, InputError> { 168 | let mut inputs = Vec::new(); 169 | let file = 170 | try!(fs::File::open(path) 171 | .map_err(|err| InputError::FileError(path.to_owned(), err.to_string()))); 172 | for line in BufReader::new(file).lines() { 173 | if let Ok(line) = line { 174 | inputs.push(line); 175 | } 176 | } 177 | Ok(inputs) 178 | } 179 | 180 | #[cfg(test)] 181 | mod test { 182 | use super::parse_arguments; 183 | 184 | #[test] 185 | fn test_parse_arguments() { 186 | let mut output = Vec::new(); 187 | let inputs = "A B ::: \"C D\" \\\"EF\\\" ::: five:six seven\\ eight"; 188 | let expected = vec![ 189 | vec!["A".to_owned(), "B".to_owned()], 190 | vec!["C D".to_owned(), "\"EF\"".to_owned()], 191 | vec!["five:six".to_owned(), "seven eight".to_owned()], 192 | ]; 193 | let _ = parse_arguments(&mut output, inputs, false); 194 | assert_eq!(output, expected); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/bin/buffer.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(unix))] 2 | pub mod platform { 3 | pub const BUFFER_SIZE: usize = 16 * 1024; // Windows only supports 16K buffers. 4 | } 5 | 6 | #[cfg(unix)] 7 | pub mod platform { 8 | pub const BUFFER_SIZE: usize = 64 * 1024; // 4.75% performance boost over 16K buffers 9 | } 10 | 11 | use self::platform::BUFFER_SIZE; 12 | use std::io::{StdoutLock, Write}; 13 | 14 | /// Manual buffer implementation for buffering standard output. 15 | pub struct StdoutBuffer { 16 | pub data: [u8; BUFFER_SIZE], 17 | pub capacity: usize, 18 | } 19 | 20 | impl StdoutBuffer { 21 | /// Create a new `Buffer` initialized to be empty. 22 | pub fn new() -> StdoutBuffer { 23 | StdoutBuffer { 24 | data: [0u8; BUFFER_SIZE], 25 | capacity: 0, 26 | } 27 | } 28 | 29 | /// Write the buffer's contents to stdout and clear itself. 30 | pub fn write_and_clear(&mut self, stdout: &mut StdoutLock) { 31 | let _ = stdout.write_all(&self.data[..]); 32 | self.data = [0u8; BUFFER_SIZE]; 33 | self.capacity = 0; 34 | } 35 | 36 | /// Write a byte slice to the buffer and mark the new size. 37 | pub fn write(&mut self, data: &[u8]) { 38 | let cap = data.len(); 39 | self.data[self.capacity..self.capacity + cap].clone_from_slice(data); 40 | self.capacity += cap; 41 | } 42 | 43 | /// Append an individual byte to the buffer, typically a space or newline. 44 | pub fn push(&mut self, data: u8) { 45 | self.data[self.capacity] = data; 46 | self.capacity += 1; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/bin/main.rs: -------------------------------------------------------------------------------- 1 | extern crate permutate; 2 | 3 | use std::io::{self, Write}; 4 | use std::process::exit; 5 | 6 | use permutate::bin; 7 | use permutate::bin::arguments::InputError; 8 | 9 | fn main() { 10 | let (input, benchmark, interpret_files, no_delimiters) = bin::arguments::parse_options(); 11 | 12 | let mut list_vector = Vec::new(); 13 | match bin::arguments::parse_arguments(&mut list_vector, &input.join(" "), interpret_files) { 14 | Ok(_) => bin::prepare(list_vector, benchmark, no_delimiters), 15 | Err(why) => { 16 | // Locking the buffers will improve performance greatly due to not needing 17 | // to worry about repeatedly locking and unlocking them throughout the program. 18 | let stderr = io::stderr(); 19 | let mut stderr = stderr.lock(); 20 | 21 | let _ = stderr.write(b"permutate: parse error: "); 22 | match why { 23 | InputError::FileError(path, why) => { 24 | let _ = stderr.write(path.as_bytes()); 25 | let _ = stderr.write(b" could not be read: "); 26 | let _ = stderr.write(why.as_bytes()); 27 | let _ = stderr.write(b".\n"); 28 | } 29 | InputError::NoInputsProvided => { 30 | let _ = stderr.write(b"no input was provided after separator.\n"); 31 | } 32 | InputError::NotEnoughInputs => { 33 | let _ = stderr.write(b"not enough inputs were provided.\n"); 34 | } 35 | } 36 | let _ = stderr.write(b"Example Usage: permutate 1 2 3 ::: 4 5 6 ::: 1 2 3\n"); 37 | exit(1); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/bin/man.rs: -------------------------------------------------------------------------------- 1 | pub const MANPAGE: &'static str = r#"NAME 2 | permutate - efficient command-line permutator written in Rust 3 | 4 | SYNOPSIS 5 | permutate [-f | -h] [ARGS... MODE]... 6 | 7 | DESCRIPTION 8 | Permutate is a command-line permutator written in Rust, originally designed for inclusion 9 | within the Rust implementation of Parallel. Following the UNIX philosophy, permutate has 10 | additionally been spun into both an application and library project to serve as a standalone 11 | application. The syntax for permutate is nearly identical to Parallel. 12 | 13 | OPTIONS 14 | -b, --benchmark 15 | Performs a benchmark by permutation all possible values without printing. 16 | 17 | -f, --files 18 | The first list of inputs will be interpreted as files. 19 | 20 | -h, --files 21 | Prints this help information. 22 | 23 | -n, --no-delimiters 24 | Disable the spaced deliminters between elements. 25 | 26 | MODES 27 | ::: 28 | All following arguments will be interpreted as arguments. 29 | 30 | :::+ 31 | All following arguments will be appended to the previous list. 32 | 33 | :::: 34 | All following arguments will be interpreted as files. 35 | 36 | ::::+ 37 | All following arguments from files will be appended to the previous list. 38 | 39 | "#; 40 | -------------------------------------------------------------------------------- /src/bin/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | pub mod arguments; 4 | pub mod buffer; 5 | pub mod man; 6 | 7 | use std::io::{self, Write}; 8 | 9 | use self::buffer::platform::BUFFER_SIZE; 10 | use self::buffer::StdoutBuffer; 11 | use crate::{ListWrapper, Permutator, PermutatorWrapper, Repeated}; 12 | 13 | pub fn prepare(list_vector: Vec>, benchmark: bool, no_delimiters: bool) -> () { 14 | type PermutatorStr<'a> = Permutator, Vec<&'a str>>; 15 | type PermutatorRepeated<'a> = Permutator, Vec<&'a str>>; 16 | 17 | if let _should_repeat @ true = list_vector.len() == 1 { 18 | // Convert the Vec> into a Vec<&str> 19 | let list_array: Vec<&str> = list_vector 20 | .iter() 21 | .next() 22 | .unwrap() 23 | .iter() 24 | .map(AsRef::as_ref) 25 | .collect(); 26 | 27 | // Convert the Vec<&str> into a [&[&str]; 1] 28 | let list_array: Repeated<_> = [list_array.as_ref()]; 29 | 30 | let mut permutator: PermutatorRepeated = Permutator::new(&list_array); 31 | if benchmark { 32 | let _ = permutator.count(); 33 | } else { 34 | if no_delimiters { 35 | permutate_without_delims(&mut permutator); 36 | } else { 37 | permutate(&mut permutator); 38 | } 39 | } 40 | } else { 41 | // Convert the Vec> into a Vec> 42 | let list_array: Vec> = list_vector 43 | .iter() 44 | .map(|list| list.iter().map(AsRef::as_ref).collect::>()) 45 | .collect(); 46 | 47 | // Convert the Vec> into a Vec<&[&str]> 48 | let list_array: Vec<&[&str]> = list_array.iter().map(AsRef::as_ref).collect(); 49 | 50 | // And then convert the `Permutator` with the &[&[&str]] as the input. 51 | let mut permutator: PermutatorStr = Permutator::new(&list_array); 52 | if benchmark { 53 | let _ = permutator.count(); 54 | } else { 55 | if no_delimiters { 56 | permutate_without_delims(&mut permutator); 57 | } else { 58 | permutate(&mut permutator); 59 | } 60 | } 61 | }; 62 | } 63 | 64 | pub fn permutate<'a, P, LW>(permutator: &'a mut P) 65 | where 66 | P: PermutatorWrapper> + Iterator>, 67 | LW: ListWrapper> + Clone, 68 | { 69 | let mut buffer = StdoutBuffer::new(); 70 | let mut current_output = permutator.next().unwrap(); 71 | // This first run through will count the number of bytes that will be 72 | // required to print each permutation to standard output. 73 | { 74 | let mut current_permutation = current_output.iter(); 75 | buffer.write(current_permutation.next().unwrap().as_bytes()); 76 | buffer.push(b' '); 77 | buffer.write(current_permutation.next().unwrap().as_bytes()); 78 | for element in current_permutation { 79 | buffer.push(b' '); 80 | buffer.write(element.as_bytes()) 81 | } 82 | } 83 | 84 | buffer.push(b'\n'); 85 | 86 | // Using the number of bytes of the first iteration, we can calculate 87 | // how many iterations that we can safely fit into our buffer. 88 | let permutations_per_buffer = BUFFER_SIZE / buffer.capacity; 89 | 90 | // Locking the buffers will improve performance greatly due to not needing 91 | // to worry about repeatedly locking and unlocking them throughout the program. 92 | let stdout = io::stdout(); 93 | let mut stdout = stdout.lock(); 94 | 95 | // Each permutation will check to see if the max number of permutations per 96 | // buffer has been allocated and prints it to standard output if true. 97 | let mut counter = 1; 98 | while let Some(current_output) = permutator.next_with_buffer(&mut current_output) { 99 | if counter == permutations_per_buffer { 100 | buffer.write_and_clear(&mut stdout); 101 | counter = 0; 102 | } 103 | 104 | // The first element will print a space after the element. 105 | let mut current_permutation = current_output.iter(); 106 | buffer.write(current_permutation.next().unwrap().as_bytes()); 107 | buffer.push(b' '); 108 | buffer.write(current_permutation.next().unwrap().as_bytes()); 109 | for element in current_permutation { 110 | buffer.push(b' '); 111 | buffer.write(element.as_bytes()) 112 | } 113 | buffer.push(b'\n'); 114 | counter += 1; 115 | } 116 | 117 | // Print the remaining buffer to standard output. 118 | let _ = stdout.write_all(&buffer.data[..]); 119 | } 120 | 121 | pub fn permutate_without_delims<'a, P, LW>(permutator: &'a mut P) 122 | where 123 | P: PermutatorWrapper> + Iterator>, 124 | LW: ListWrapper> + Clone, 125 | { 126 | // This first run through will count the number of bytes that will be 127 | // required to print each permutation to standard output. 128 | let mut buffer = StdoutBuffer::new(); 129 | let mut current_output = permutator.next().unwrap(); 130 | { 131 | // There will always be at least two elements in a permutation. 132 | let mut permutation = current_output.iter(); 133 | buffer.write(permutation.next().unwrap().as_bytes()); 134 | buffer.write(permutation.next().unwrap().as_bytes()); 135 | for element in permutation { 136 | buffer.write(element.as_bytes()); 137 | } 138 | } 139 | 140 | // Append a newline after each permutation to print them on separate lines. 141 | buffer.push(b'\n'); 142 | 143 | // Using the number of bytes of the first iteration, we can calculate 144 | // how many iterations that we can safely fit into our buffer. 145 | let permutations_per_buffer = BUFFER_SIZE / buffer.capacity; 146 | 147 | // Locking the buffers will improve performance greatly due to not needing 148 | // to worry about repeatedly locking and unlocking them throughout the program. 149 | let stdout = io::stdout(); 150 | let mut stdout = stdout.lock(); 151 | 152 | // Each permutation will check to see if the max number of permutations per 153 | // buffer has been allocated and prints it to standard output if true. 154 | let mut counter = 1; 155 | while let Some(current_output) = permutator.next_with_buffer(&mut current_output) { 156 | let mut permutation = current_output.iter(); 157 | if counter == permutations_per_buffer { 158 | buffer.write_and_clear(&mut stdout); 159 | counter = 0; 160 | } 161 | 162 | // There will always be at least two elements in a permutation. 163 | buffer.write(permutation.next().unwrap().as_bytes()); 164 | buffer.write(permutation.next().unwrap().as_bytes()); 165 | for element in permutation { 166 | buffer.write(element.as_bytes()); 167 | } 168 | buffer.push(b'\n'); 169 | counter += 1; 170 | } 171 | 172 | // Print the remaining buffer to standard output. 173 | let _ = stdout.write_all(&buffer.data[..]); 174 | } 175 | -------------------------------------------------------------------------------- /src/index_counters.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Debug)] 2 | /// Tracks the state of the indexes of each list. 3 | pub struct IndexCounters { 4 | /// The current state of the indexes 5 | pub indexes: Vec, 6 | /// The lengths of the wrapped lists 7 | pub lens: Vec, 8 | /// The current iteration position 9 | pub curr_iter: usize, 10 | /// The maximum number of iterations to perform 11 | pub max_iters: usize, 12 | } 13 | 14 | impl IndexCounters { 15 | /// Increments & resets index indexes according to their maximum values. 16 | pub fn increment(&mut self, mut nlists: usize) { 17 | loop { 18 | let mut increment = false; 19 | { 20 | let current = unsafe { self.indexes.get_unchecked_mut(nlists) }; 21 | let max = unsafe { self.lens.get_unchecked(nlists) }; 22 | if *current + 1 >= *max { 23 | if nlists != 0 { 24 | *current = 0; 25 | increment = true; 26 | } 27 | } else { 28 | *current += 1; 29 | } 30 | } 31 | 32 | if increment { 33 | nlists -= 1; 34 | } else { 35 | break; 36 | } 37 | } 38 | } 39 | 40 | pub fn reset(&mut self) { 41 | for value in self.indexes.iter_mut() { 42 | *value = 0; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(external_doc)] 2 | #![doc(include = "../README.md")] 3 | #![deny(missing_docs)] 4 | 5 | /// Utilities to be used by the binary and benchmarking. 6 | #[cfg(feature = "bin-utils")] 7 | pub mod bin; 8 | 9 | use std::marker::PhantomData; 10 | 11 | mod index_counters; 12 | mod list_wrapper; 13 | 14 | use index_counters::IndexCounters; 15 | pub use list_wrapper::{ListWrapper, Repeated}; 16 | 17 | /// The `PermutatorWrapper` contains the methods (creation, etc) which any Permutator should 18 | /// implement. 19 | pub trait PermutatorWrapper 20 | where 21 | ListWrap: ListWrapper, 22 | ListWrap: ListWrapper + ?Sized + Clone, 23 | { 24 | /// Initialize a new `Permutator` with the vec/tuple of input slices to permutate with. 25 | /// The input may be provided as either multiple lists via a vec/tuple of slices, or a single 26 | /// list as an slice within an array. 27 | fn new(lists: &ListWrap) -> Permutator; 28 | 29 | /// Sets the internal index counter's values to a specific state, which you will 30 | /// typically obtain when using the `get_index()` method. The `iter_no` parameter 31 | /// will specify what the iteration's position should be. If, for example, you set 32 | /// this value to `0`, then it will iterate through all possible permutations, 33 | /// including looping around back to the beginning and generating permutations 34 | /// for all possible values before the supplied state. 35 | /// 36 | /// # Panics 37 | /// This method will panic if the supplied indexes vector is not the correct length 38 | fn set_index(&mut self, iter_no: usize, indexes: Vec); 39 | 40 | /// Obtains the current iteration number and the index counter's indexes. 41 | fn get_index(&self) -> (usize, Vec); 42 | 43 | /// Returns the total number of permutations possible 44 | fn max_permutations(&self) -> usize; 45 | 46 | /// Resets the internal state of the `Permutator` to allow you to start permutating again. 47 | fn reset(&mut self); 48 | 49 | /// Provides similar functionality as the `Iterator` traits `next` method, but allows the 50 | /// ability to either supply your own buffer or re-use the `Vec`/`tuple` created by a prior 51 | /// `next` in order to avoid extra allocations. 52 | /// 53 | /// If there were more methods to compute, then the buffer mutable borrow is returned. 54 | /// Otherwise, None is returned. 55 | /// 56 | /// # Panics 57 | /// This method will panic if the supplied buffer's length is invalid. 58 | fn next_with_buffer<'b>(&mut self, buffer: &'b mut ItemWrap) -> Option<&'b mut ItemWrap>; 59 | } 60 | 61 | /// The `Permutator` contains the state of the iterator as well as the owned values and/or 62 | /// references of inputs that are being permutated. The input should be provided as a vector or 63 | /// tuple of slices of values (or references). 64 | #[derive(Clone, Debug)] 65 | pub struct Permutator 66 | where 67 | ListWrap: ListWrapper, 68 | { 69 | /// The indexes is used to point to the next permutation sequence. 70 | indexes: IndexCounters, 71 | /// The internal data that the permutator is permutating against. 72 | lists: ListWrap, 73 | /// Phantom type, so that when implementing the `Iterator` for this structure, 74 | /// `ItemWrap` type may be used as `Iterator::Item`. 75 | _list_item_wrapper: PhantomData, 76 | } 77 | 78 | impl PermutatorWrapper for Permutator 79 | where 80 | ListWrap: ListWrapper + ?Sized + Clone, 81 | { 82 | fn new(lists: &ListWrap) -> Permutator { 83 | let nlists = lists.wrapper_len(); 84 | let nvalues = lists.lens(); 85 | let max_iters = nvalues.iter().product(); 86 | 87 | Permutator { 88 | indexes: IndexCounters { 89 | indexes: vec![0; nlists], 90 | lens: nvalues, 91 | curr_iter: 0, 92 | max_iters: max_iters, 93 | }, 94 | lists: lists.clone(), 95 | _list_item_wrapper: PhantomData, 96 | } 97 | } 98 | 99 | fn set_index(&mut self, iter_no: usize, indexes: Vec) { 100 | debug_assert!( 101 | indexes.len() == self.indexes.lens.len(), 102 | "indexes have an invalid length" 103 | ); 104 | self.indexes.indexes = indexes; 105 | self.indexes.curr_iter = iter_no; 106 | } 107 | 108 | /// Obtains the current iteration number and the index counter's indexes. 109 | fn get_index(&self) -> (usize, Vec) { 110 | (self.indexes.curr_iter, self.indexes.indexes.clone()) 111 | } 112 | 113 | /// Returns the total number of permutations possible 114 | fn max_permutations(&self) -> usize { 115 | self.indexes.max_iters 116 | } 117 | 118 | /// Resets the internal state of the `Permutator` to allow you to start permutating again. 119 | fn reset(&mut self) { 120 | self.indexes.reset(); 121 | self.indexes.curr_iter = 0; 122 | } 123 | 124 | fn next_with_buffer<'b>(&mut self, buffer: &'b mut ItemWrap) -> Option<&'b mut ItemWrap> { 125 | if self.indexes.max_iters != 0 && self.indexes.curr_iter == self.indexes.max_iters { 126 | return None; 127 | } 128 | 129 | self.indexes.curr_iter += 1; 130 | let self_lists: &mut _ = &mut self.lists; 131 | ListWrap::next_with_buffer(self_lists, &self.indexes.indexes, buffer); 132 | self.indexes.increment(self_lists.wrapper_len() - 1); 133 | Some(buffer) 134 | } 135 | } 136 | 137 | impl Iterator for Permutator 138 | where 139 | ListWrap: ListWrapper, 140 | { 141 | type Item = ItemWrap; 142 | 143 | fn nth(&mut self, mut n: usize) -> Option { 144 | loop { 145 | if self.indexes.max_iters != 0 && self.indexes.curr_iter == self.indexes.max_iters { 146 | return None; 147 | } 148 | 149 | self.indexes.curr_iter += 1; 150 | 151 | if let _should_skip @ true = n != 0 { 152 | self.indexes.increment(&self.lists.wrapper_len() - 1); 153 | n -= 1; 154 | } else { 155 | let output = ListWrap::next_item(&self.lists, &self.indexes.indexes); 156 | self.indexes.increment(&self.lists.wrapper_len() - 1); 157 | return Some(output); 158 | } 159 | } 160 | } 161 | 162 | fn next(&mut self) -> Option { 163 | // Without this check, the permutator would cycle forever and never return `None` 164 | // because my incrementing algorithim prohibits it. 165 | if self.indexes.max_iters != 0 && self.indexes.curr_iter == self.indexes.max_iters { 166 | return None; 167 | } 168 | 169 | self.indexes.curr_iter += 1; 170 | // Generates the next permutation sequence using the current indexes. 171 | let output = ListWrap::next_item(&self.lists, &self.indexes.indexes); 172 | 173 | // Increment the indexes to point towards the next set of values. 174 | self.indexes.increment(self.lists.wrapper_len() - 1); 175 | 176 | // Return the collected permutation 177 | Some(output) 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/list_wrapper.rs: -------------------------------------------------------------------------------- 1 | mod single_list; 2 | mod tuple_of_lists; 3 | mod vec_of_lists; 4 | 5 | // re-export 6 | pub use self::single_list::Repeated; 7 | 8 | /// Abstract the outermost slice(s) wrapper behaviour. 9 | /// eg. Accesses on `Vec` slice wrappers are different from `tuple` slice wrappers. 10 | pub trait ListWrapper 11 | where 12 | ItemWrap: Sized, 13 | { 14 | /// The total number of slices that are being permutated with. 15 | fn wrapper_len(&self) -> usize; 16 | /// The length of each slices that are being permutated with. 17 | fn lens(&self) -> Vec; 18 | /// Get values according to the given `indexes`. 19 | fn next_item(&self, indexes: &Vec) -> ItemWrap; 20 | /// Same as `next_item`, but doesn't allocates for the returning `ItemWrap`. 21 | fn next_with_buffer(&self, indexes: &Vec, buffer: &mut ItemWrap) -> (); 22 | } 23 | -------------------------------------------------------------------------------- /src/list_wrapper/single_list.rs: -------------------------------------------------------------------------------- 1 | use ListWrapper; 2 | 3 | type OneSized<'a, T> = [&'a [T]; 1]; 4 | 5 | /// Indicates that the permutator will repeated the input and read it as a 6 | /// square-sized matrix. 7 | /// 8 | /// # Example 9 | /// 10 | /// ```rust 11 | /// # use permutate::{Repeated, Permutator, PermutatorWrapper as _}; 12 | /// # 13 | /// // the permutator `pv`, which indicates the `Repeated` type, 14 | /// let v = [&["1", "2", "3"][..]]; 15 | /// let pv = Permutator::, _>::new(&v); 16 | /// 17 | /// // will have the same output as the permutator `pm`, 18 | /// // which does not indicates the `Repeated` type: 19 | /// let m = [&["1", "2", "3"][..], &["1", "2", "3"][..], &["1", "2", "3"][..]]; 20 | /// let pm = Permutator::<_, _>::new(&m.to_vec()); 21 | /// 22 | /// // and such output is: 23 | /// let output = [ 24 | /// &["1", "1", "1"][..], &["1", "1", "2"][..], &["1", "1", "3"][..], 25 | /// &["1", "2", "1"][..], &["1", "2", "2"][..], &["1", "2", "3"][..], 26 | /// &["1", "3", "1"][..], &["1", "3", "2"][..], &["1", "3", "3"][..], 27 | /// &["2", "1", "1"][..], &["2", "1", "2"][..], &["2", "1", "3"][..], 28 | /// &["2", "2", "1"][..], &["2", "2", "2"][..], &["2", "2", "3"][..], 29 | /// &["2", "3", "1"][..], &["2", "3", "2"][..], &["2", "3", "3"][..], 30 | /// &["3", "1", "1"][..], &["3", "1", "2"][..], &["3", "1", "3"][..], 31 | /// &["3", "2", "1"][..], &["3", "2", "2"][..], &["3", "2", "3"][..], 32 | /// &["3", "3", "1"][..], &["3", "3", "2"][..], &["3", "3", "3"][..], 33 | /// ]; 34 | /// # 35 | /// # pv.zip(pm).zip(output[..].iter()).for_each(|((v, m), o)| { 36 | /// # assert_eq!(v, m); 37 | /// # assert_eq!(&v, o); 38 | /// # }); 39 | /// ``` 40 | /// 41 | /// # Math perspective 42 | /// 43 | /// This is the same as `(diag(V) x Ones) transposed` math operation, 44 | /// where 45 | /// - `V` is a vector `1xn`, 46 | /// - `diag(V)` is the `DiagonalMatrix` operation 47 | /// which maps each element from `Vj` into a 2d-matrix `nxn` at position `jxj`, 48 | /// - `Ones` is a all-ones matrix `nxn`, 49 | /// - `transposed` operation transposes the matrix that precedes it. 50 | pub type Repeated<'a, T> = OneSized<'a, T>; 51 | 52 | // implementation for when it's a single list 53 | impl<'a, T> ListWrapper> for OneSized<'a, T> 54 | where 55 | T: ?Sized + Copy, 56 | { 57 | fn wrapper_len(&self) -> usize { 58 | let len = self[0].len(); 59 | debug_assert!(len != 0); 60 | len 61 | } 62 | fn lens(&self) -> Vec { 63 | let nlists = self[0].len(); 64 | debug_assert!(nlists != 0); 65 | (0..nlists).map(|_| nlists).collect::>() 66 | } 67 | fn next_item(&self, indexes: &Vec) -> Vec { 68 | // We are using `get_unchecked()` here because the incrementing 69 | // algorithim prohibits values from being out of bounds. 70 | indexes 71 | .iter() 72 | .map(|value| unsafe { *self[0].get_unchecked(*value) }) 73 | .collect::>() 74 | } 75 | fn next_with_buffer(&self, indexes: &Vec, buffer: &mut Vec) -> () { 76 | debug_assert!( 77 | buffer.len() >= self.wrapper_len(), 78 | "bufferis not large enough to contain the permutation" 79 | ); 80 | 81 | let mut index = 0; 82 | // We are using `get_unchecked()` here because the incrementing 83 | // algorithim prohibits values from being out of bounds. 84 | unsafe { 85 | for outer_value in indexes.iter().map(|value| *self[0].get_unchecked(*value)) { 86 | *buffer.get_unchecked_mut(index) = outer_value; 87 | index += 1; 88 | } 89 | }; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/list_wrapper/tuple_of_lists.rs: -------------------------------------------------------------------------------- 1 | use ListWrapper; 2 | 3 | // reference: https://doc.rust-lang.org/src/core/tuple.rs.html 4 | macro_rules! tuple_impls { 5 | ($( 6 | $Tuple:ident { 7 | $(($idx:tt) -> $T:ident)+ 8 | } 9 | )+) => { 10 | $( 11 | impl<'a, $($T),+> ListWrapper<($($T,)+)> for ($(&'a [$T],)+) 12 | where 13 | $($T: ?Sized + Copy,)+ 14 | // &'a Self: Sized, 15 | { 16 | fn wrapper_len(&self) -> usize { 17 | tuple_impls!(@last_idx $($idx,)+) + 1 18 | } 19 | fn lens(&self) -> Vec { 20 | let ls = vec![$(self.$idx.len()),+]; 21 | ls.iter().for_each(|l| debug_assert!(*l != 0)); 22 | ls 23 | } 24 | fn next_item(&self, indexes: &Vec) -> ($($T,)+) { 25 | // We are using `get_unchecked()` here because the incrementing 26 | // algorithim prohibits values from being out of bounds. 27 | unsafe { 28 | ( 29 | $(*self.$idx.get_unchecked(indexes[$idx]),)+ 30 | ) 31 | } 32 | } 33 | 34 | 35 | fn next_with_buffer( 36 | &self, 37 | indexes: &Vec, 38 | buffer: &mut ($($T,)+), 39 | ) -> () { 40 | // `nlists` verification is unnecessary because it's verified 41 | // at compile-time 42 | 43 | // We are using `get_unchecked()` here because the incrementing 44 | // algorithim prohibits values from being out of bounds. 45 | unsafe { 46 | $( 47 | buffer.$idx = *self.$idx.get_unchecked(indexes[$idx]); 48 | )+ 49 | } 50 | } 51 | } 52 | 53 | 54 | )+ 55 | }; 56 | 57 | // this returns the last idx from a list of idx 58 | (@last_idx $a:tt,) => { $a }; 59 | (@last_idx $a:tt, $($rest_a:tt,)+) => { tuple_impls!(@last_idx $($rest_a,)+) }; 60 | // additional reference: https://danielkeep.github.io/tlborm/book/pat-internal-rules.html 61 | } 62 | 63 | tuple_impls! { 64 | Tuple1 { 65 | (0) -> A 66 | } 67 | Tuple2 { 68 | (0) -> A 69 | (1) -> B 70 | } 71 | Tuple3 { 72 | (0) -> A 73 | (1) -> B 74 | (2) -> C 75 | } 76 | Tuple4 { 77 | (0) -> A 78 | (1) -> B 79 | (2) -> C 80 | (3) -> D 81 | } 82 | Tuple5 { 83 | (0) -> A 84 | (1) -> B 85 | (2) -> C 86 | (3) -> D 87 | (4) -> E 88 | } 89 | Tuple6 { 90 | (0) -> A 91 | (1) -> B 92 | (2) -> C 93 | (3) -> D 94 | (4) -> E 95 | (5) -> F 96 | } 97 | Tuple7 { 98 | (0) -> A 99 | (1) -> B 100 | (2) -> C 101 | (3) -> D 102 | (4) -> E 103 | (5) -> F 104 | (6) -> G 105 | } 106 | Tuple8 { 107 | (0) -> A 108 | (1) -> B 109 | (2) -> C 110 | (3) -> D 111 | (4) -> E 112 | (5) -> F 113 | (6) -> G 114 | (7) -> H 115 | } 116 | Tuple9 { 117 | (0) -> A 118 | (1) -> B 119 | (2) -> C 120 | (3) -> D 121 | (4) -> E 122 | (5) -> F 123 | (6) -> G 124 | (7) -> H 125 | (8) -> I 126 | } 127 | Tuple10 { 128 | (0) -> A 129 | (1) -> B 130 | (2) -> C 131 | (3) -> D 132 | (4) -> E 133 | (5) -> F 134 | (6) -> G 135 | (7) -> H 136 | (8) -> I 137 | (9) -> J 138 | } 139 | Tuple11 { 140 | (0) -> A 141 | (1) -> B 142 | (2) -> C 143 | (3) -> D 144 | (4) -> E 145 | (5) -> F 146 | (6) -> G 147 | (7) -> H 148 | (8) -> I 149 | (9) -> J 150 | (10) -> K 151 | } 152 | Tuple12 { 153 | (0) -> A 154 | (1) -> B 155 | (2) -> C 156 | (3) -> D 157 | (4) -> E 158 | (5) -> F 159 | (6) -> G 160 | (7) -> H 161 | (8) -> I 162 | (9) -> J 163 | (10) -> K 164 | (11) -> L 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/list_wrapper/vec_of_lists.rs: -------------------------------------------------------------------------------- 1 | use ListWrapper; 2 | 3 | // implementation for lists of lists 4 | impl ListWrapper> for Vec<&[T]> 5 | where 6 | T: ?Sized + Copy, 7 | { 8 | fn wrapper_len(&self) -> usize { 9 | let len = self.len(); 10 | debug_assert!(len != 0); 11 | len 12 | } 13 | fn lens(&self) -> Vec { 14 | self.iter() 15 | .map(|list| { 16 | let len = list.len(); 17 | debug_assert!(len != 0); 18 | len 19 | }) 20 | .collect::>() 21 | } 22 | fn next_item(&self, indexes: &Vec) -> Vec { 23 | // We are using `get_unchecked()` here because the incrementing 24 | // algorithim prohibits values from being out of bounds. 25 | indexes 26 | .iter() 27 | .enumerate() 28 | .map(|(list, value)| unsafe { *self.get_unchecked(list).get_unchecked(*value) }) 29 | .collect::>() 30 | } 31 | 32 | fn next_with_buffer(&self, indexes: &Vec, buffer: &mut Vec) -> () { 33 | debug_assert!( 34 | buffer.len() >= self.wrapper_len(), 35 | "buffer is not large enough to contain the permutation" 36 | ); 37 | 38 | let mut index = 0; 39 | // We are using `get_unchecked()` here because the incrementing 40 | // algorithim prohibits values from being out of bounds. 41 | unsafe { 42 | for outer_value in indexes 43 | .iter() 44 | .enumerate() 45 | .map(|(list, value)| *self.get_unchecked(list).get_unchecked(*value)) 46 | { 47 | *buffer.get_unchecked_mut(index) = outer_value; 48 | index += 1; 49 | } 50 | }; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/million_permutations.rs: -------------------------------------------------------------------------------- 1 | extern crate permutate; 2 | use permutate::{Permutator, PermutatorWrapper as _}; 3 | 4 | fn get_input<'a>() -> [&'a [&'a str]; 6] { 5 | [ 6 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 10 7 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 100 8 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 1k 9 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 10k 10 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 100k 11 | &["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"][..], // 1M 12 | ] 13 | } 14 | 15 | #[test] 16 | // Check to see if exactly 1,000,000 permutations were collected. 17 | fn test_million_permutations() { 18 | let input: Vec<&[&str]> = get_input().to_vec(); 19 | assert_eq!(1_000_000, Permutator::new(&input).count()) 20 | } 21 | -------------------------------------------------------------------------------- /tests/permutation_values.rs: -------------------------------------------------------------------------------- 1 | extern crate permutate; 2 | use permutate::{Permutator, PermutatorWrapper as _}; 3 | 4 | fn get_input<'a>() -> [&'a [&'a str]; 3] { 5 | [ 6 | &["1", "2", "3"][..], 7 | &["1", "2", "3"][..], 8 | &["1", "2", "3"][..], 9 | ] 10 | } 11 | 12 | fn get_expected<'a>() -> [&'a [&'a str]; 27] { 13 | [ 14 | &["1", "1", "1"][..], 15 | &["1", "1", "2"][..], 16 | &["1", "1", "3"][..], 17 | &["1", "2", "1"][..], 18 | &["1", "2", "2"][..], 19 | &["1", "2", "3"][..], 20 | &["1", "3", "1"][..], 21 | &["1", "3", "2"][..], 22 | &["1", "3", "3"][..], 23 | &["2", "1", "1"][..], 24 | &["2", "1", "2"][..], 25 | &["2", "1", "3"][..], 26 | &["2", "2", "1"][..], 27 | &["2", "2", "2"][..], 28 | &["2", "2", "3"][..], 29 | &["2", "3", "1"][..], 30 | &["2", "3", "2"][..], 31 | &["2", "3", "3"][..], 32 | &["3", "1", "1"][..], 33 | &["3", "1", "2"][..], 34 | &["3", "1", "3"][..], 35 | &["3", "2", "1"][..], 36 | &["3", "2", "2"][..], 37 | &["3", "2", "3"][..], 38 | &["3", "3", "1"][..], 39 | &["3", "3", "2"][..], 40 | &["3", "3", "3"][..], 41 | ] 42 | } 43 | 44 | #[test] 45 | // Verify that the permutations are generated with the correct values, 46 | // in the correct order. 47 | fn test_permutation_values() { 48 | let input = get_input().to_vec(); 49 | let expected = get_expected(); 50 | 51 | for (output, expected) in Permutator::new(&input).zip(expected[..].iter()) { 52 | assert_eq!(&output, expected); 53 | 54 | // also assert that for each value pair, both point to the same address 55 | for (o, e) in (*output).iter().zip(&expected[..]) { 56 | assert_eq!(*o as *const str, *e as *const str); 57 | } 58 | } 59 | 60 | let mut permutator = Permutator::new(&input); 61 | let mut expected = expected[..].iter(); 62 | assert_eq!(&(permutator.nth(10).unwrap()), expected.nth(10).unwrap()); 63 | assert_eq!(&(permutator.nth(0).unwrap()), expected.nth(0).unwrap()); 64 | } 65 | 66 | #[test] 67 | // Verify that the permutations are generated with the correct values, 68 | // in the correct order re-using the permutation buffer. 69 | fn test_permutation_values_with_buffer() { 70 | let input = get_input().to_vec(); 71 | let expected = get_expected(); 72 | 73 | let mut permutator = Permutator::new(&input); 74 | let mut expected_iterator = expected[..].iter(); 75 | 76 | if let Some(mut permutation) = permutator.next() { 77 | let expected_permutation = expected_iterator.next().unwrap(); 78 | assert_eq!(&permutation, expected_permutation); 79 | 80 | // also assert that for each value pair, both point to the same address 81 | for (o, e) in (*permutation).iter().zip(*expected_permutation) { 82 | assert_eq!(*o as *const str, *e as *const str); 83 | } 84 | 85 | while let Some(permutation) = permutator.next_with_buffer(&mut permutation) { 86 | let expected_permutation = expected_iterator.next().unwrap(); 87 | assert_eq!(&permutation, &expected_permutation); 88 | 89 | // also assert that for each value pair, both point to the same address 90 | for (o, e) in (*permutation).iter().zip(*expected_permutation) { 91 | assert_eq!(*o as *const str, *e as *const str); 92 | } 93 | } 94 | } 95 | 96 | // verifies that the expected iterator has been fully consumed 97 | assert!(expected_iterator.next().is_none()); 98 | } 99 | 100 | fn get_input_b<'a>() -> [&'a [&'a str]; 4] { 101 | [ 102 | &["0", "1"][..], 103 | &["A", "B"][..], 104 | &["a", "b", "c"][..], 105 | &["_"][..], 106 | ] 107 | } 108 | 109 | fn get_expected_b<'a>() -> [&'a [&'a str]; 12] { 110 | [ 111 | &["0", "A", "a", "_"], 112 | &["0", "A", "b", "_"], 113 | &["0", "A", "c", "_"], 114 | &["0", "B", "a", "_"], 115 | &["0", "B", "b", "_"], 116 | &["0", "B", "c", "_"], 117 | &["1", "A", "a", "_"], 118 | &["1", "A", "b", "_"], 119 | &["1", "A", "c", "_"], 120 | &["1", "B", "a", "_"], 121 | &["1", "B", "b", "_"], 122 | &["1", "B", "c", "_"], 123 | ] 124 | } 125 | 126 | #[test] 127 | // Verify that the permutations are generated with the correct values, 128 | // in the correct order. 129 | fn test_permutation_values_b() { 130 | let input = get_input_b().to_vec(); 131 | let expected = get_expected_b(); 132 | 133 | for (output, expected) in Permutator::new(&input).zip(expected[..].iter()) { 134 | assert_eq!(&output, expected); 135 | 136 | // also assert that for each value pair, both point to the same address 137 | for (o, e) in (*output).iter().zip(&expected[..]) { 138 | assert_eq!(*o as *const str, *e as *const str); 139 | } 140 | } 141 | } 142 | 143 | #[test] 144 | // Verify that the permutations are generated with the correct values, 145 | // in the correct order. 146 | fn test_permutation_values_b_derefs() { 147 | let input = get_input_b().to_vec(); 148 | let expected = get_expected_b(); 149 | 150 | for (output, expected) in 151 | Permutator::, _>::new(&&&&&&input).zip(expected[..].iter()) 152 | { 153 | assert_eq!(&output, expected); 154 | 155 | // also assert that for each value pair, both point to the same address 156 | for (o, e) in (*output).iter().zip(&expected[..]) { 157 | assert_eq!(*o as *const str, *e as *const str); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /tests/reset.rs: -------------------------------------------------------------------------------- 1 | extern crate permutate; 2 | use permutate::{Permutator, PermutatorWrapper as _, Repeated}; 3 | 4 | fn get_input<'a>() -> [&'a [&'a str]; 1] { 5 | [&["1", "2", "3"][..]] 6 | } 7 | 8 | fn get_expected<'a>() -> [&'a [&'a str]; 27] { 9 | [ 10 | &["1", "1", "1"][..], 11 | &["1", "1", "2"][..], 12 | &["1", "1", "3"][..], 13 | &["1", "2", "1"][..], 14 | &["1", "2", "2"][..], 15 | &["1", "2", "3"][..], 16 | &["1", "3", "1"][..], 17 | &["1", "3", "2"][..], 18 | &["1", "3", "3"][..], 19 | &["2", "1", "1"][..], 20 | &["2", "1", "2"][..], 21 | &["2", "1", "3"][..], 22 | &["2", "2", "1"][..], 23 | &["2", "2", "2"][..], 24 | &["2", "2", "3"][..], 25 | &["2", "3", "1"][..], 26 | &["2", "3", "2"][..], 27 | &["2", "3", "3"][..], 28 | &["3", "1", "1"][..], 29 | &["3", "1", "2"][..], 30 | &["3", "1", "3"][..], 31 | &["3", "2", "1"][..], 32 | &["3", "2", "2"][..], 33 | &["3", "2", "3"][..], 34 | &["3", "3", "1"][..], 35 | &["3", "3", "2"][..], 36 | &["3", "3", "3"][..], 37 | ] 38 | } 39 | 40 | #[test] 41 | fn test_reset() { 42 | let input = get_input(); 43 | let expected = get_expected(); 44 | let mut permutator = Permutator::, _>::new(&input); 45 | for (output, expected) in permutator.by_ref().zip(expected[..].iter()) { 46 | assert_eq!(&output, expected); 47 | 48 | // also assert that for each value pair, both point to the same address 49 | for (o, e) in (*output).iter().zip(&expected[..]) { 50 | assert_eq!(*o as *const str, *e as *const str); 51 | } 52 | } 53 | permutator.reset(); 54 | for (output, expected) in permutator.zip(expected[..].iter()) { 55 | assert_eq!(&output, expected); 56 | 57 | // also assert that for each value pair, both point to the same address 58 | for (o, e) in (*output).iter().zip(&expected[..]) { 59 | assert_eq!(*o as *const str, *e as *const str); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/single_list_permutation.rs: -------------------------------------------------------------------------------- 1 | extern crate permutate; 2 | use permutate::{Permutator, PermutatorWrapper as _, Repeated}; 3 | 4 | fn get_input<'a>() -> [&'a [&'a str]; 1] { 5 | [&["1", "2", "3"][..]] 6 | } 7 | 8 | fn get_expected<'a>() -> [&'a [&'a str]; 27] { 9 | [ 10 | &["1", "1", "1"][..], 11 | &["1", "1", "2"][..], 12 | &["1", "1", "3"][..], 13 | &["1", "2", "1"][..], 14 | &["1", "2", "2"][..], 15 | &["1", "2", "3"][..], 16 | &["1", "3", "1"][..], 17 | &["1", "3", "2"][..], 18 | &["1", "3", "3"][..], 19 | &["2", "1", "1"][..], 20 | &["2", "1", "2"][..], 21 | &["2", "1", "3"][..], 22 | &["2", "2", "1"][..], 23 | &["2", "2", "2"][..], 24 | &["2", "2", "3"][..], 25 | &["2", "3", "1"][..], 26 | &["2", "3", "2"][..], 27 | &["2", "3", "3"][..], 28 | &["3", "1", "1"][..], 29 | &["3", "1", "2"][..], 30 | &["3", "1", "3"][..], 31 | &["3", "2", "1"][..], 32 | &["3", "2", "2"][..], 33 | &["3", "2", "3"][..], 34 | &["3", "3", "1"][..], 35 | &["3", "3", "2"][..], 36 | &["3", "3", "3"][..], 37 | ] 38 | } 39 | 40 | fn get_expected_b<'a>() -> [&'a [&'a str]; 3] { 41 | [&["1"][..], &["2"][..], &["3"][..]] 42 | } 43 | 44 | #[test] 45 | fn single_list_permutation() { 46 | let input = get_input(); 47 | let expected = get_expected(); 48 | 49 | for (output, expected) in Permutator::, _>::new(&input).zip(expected[..].iter()) { 50 | assert_eq!(&output, expected); 51 | 52 | // also assert that for each value pair, both point to the same address 53 | for (o, e) in (*output).iter().zip(&expected[..]) { 54 | assert_eq!(*o as *const str, *e as *const str); 55 | } 56 | } 57 | } 58 | 59 | #[test] 60 | fn single_list_permutation_with_buffer() { 61 | let input = get_input(); 62 | let expected = get_expected(); 63 | 64 | let mut permutator = Permutator::, _>::new(&input); 65 | let mut expected_iterator = expected[..].iter(); 66 | 67 | if let Some(mut permutation) = permutator.next() { 68 | let expected_permutation = expected_iterator.next().unwrap(); 69 | assert_eq!(&permutation, expected_permutation); 70 | 71 | // also assert that for each value pair, both point to the same address 72 | for (o, e) in (*permutation).iter().zip(*expected_permutation) { 73 | assert_eq!(*o as *const str, *e as *const str); 74 | } 75 | 76 | while let Some(permutation) = permutator.next_with_buffer(&mut permutation) { 77 | let expected_permutation = expected_iterator.next().unwrap(); 78 | assert_eq!(&permutation.as_slice(), expected_permutation); 79 | 80 | // also assert that for each value pair, both point to the same address 81 | for (o, e) in (*permutation).iter().zip(*expected_permutation) { 82 | assert_eq!(*o as *const str, *e as *const str); 83 | } 84 | } 85 | } 86 | 87 | // verifies that the expected iterator has been fully consumed 88 | assert!(expected_iterator.next().is_none()) 89 | } 90 | 91 | #[test] 92 | fn single_list_permutation_b() { 93 | let input = get_input().to_vec(); 94 | let expected = get_expected_b(); 95 | for (output, expected) in Permutator::new(&input).zip(expected[..].iter()) { 96 | assert_eq!(&output, expected); 97 | 98 | // also assert that for each value pair, both point to the same address 99 | for (o, e) in (*output).iter().zip(*expected) { 100 | assert_eq!(*o as *const str, *e as *const str); 101 | } 102 | } 103 | } 104 | 105 | #[test] 106 | fn single_list_permutation_b_with_buffer() { 107 | let input = get_input().to_vec(); 108 | let expected = get_expected_b(); 109 | 110 | let mut permutator = Permutator::new(&input); 111 | let mut expected_iterator = expected[..].iter(); 112 | 113 | if let Some(mut permutation) = permutator.next() { 114 | let expected_permutation = expected_iterator.next().unwrap(); 115 | assert_eq!(&permutation, expected_permutation); 116 | 117 | // also assert that for each value pair, both point to the same address 118 | for (o, e) in (*permutation).iter().zip(*expected_permutation) { 119 | assert_eq!(*o as *const str, *e as *const str); 120 | } 121 | 122 | while let Some(permutation) = permutator.next_with_buffer(&mut permutation) { 123 | let expected_permutation = expected_iterator.next().unwrap(); 124 | assert_eq!(&permutation, &expected_permutation); 125 | 126 | // also assert that for each value pair, both point to the same address 127 | for (o, e) in (*permutation).iter().zip(*expected_permutation) { 128 | assert_eq!(*o as *const str, *e as *const str); 129 | } 130 | } 131 | } 132 | 133 | // verifies that the expected iterator has been fully consumed 134 | assert!(expected_iterator.next().is_none()) 135 | } 136 | 137 | fn get_input_c<'a>() -> [&'a [i32]; 1] { 138 | [&[1, 2, 3][..]] 139 | } 140 | 141 | fn get_expected_c<'a>() -> [&'a [i32]; 27] { 142 | [ 143 | &[1, 1, 1][..], 144 | &[1, 1, 2][..], 145 | &[1, 1, 3][..], 146 | &[1, 2, 1][..], 147 | &[1, 2, 2][..], 148 | &[1, 2, 3][..], 149 | &[1, 3, 1][..], 150 | &[1, 3, 2][..], 151 | &[1, 3, 3][..], 152 | &[2, 1, 1][..], 153 | &[2, 1, 2][..], 154 | &[2, 1, 3][..], 155 | &[2, 2, 1][..], 156 | &[2, 2, 2][..], 157 | &[2, 2, 3][..], 158 | &[2, 3, 1][..], 159 | &[2, 3, 2][..], 160 | &[2, 3, 3][..], 161 | &[3, 1, 1][..], 162 | &[3, 1, 2][..], 163 | &[3, 1, 3][..], 164 | &[3, 2, 1][..], 165 | &[3, 2, 2][..], 166 | &[3, 2, 3][..], 167 | &[3, 3, 1][..], 168 | &[3, 3, 2][..], 169 | &[3, 3, 3][..], 170 | ] 171 | } 172 | 173 | #[test] 174 | // Verify that the permutations are generated with the correct values, 175 | // in the correct order. 176 | fn test_value_owned_permutation() { 177 | let input = get_input_c(); 178 | let expected = get_expected_c(); 179 | 180 | for (output, expected) in Permutator::, _>::new(&input).zip(expected[..].iter()) { 181 | assert_eq!(&output, expected); 182 | 183 | // also assert that for each value pair, they have different addresses 184 | for (o, e) in (*output).iter().zip(&expected[..]) { 185 | assert!(o as *const i32 != e as *const i32); 186 | } 187 | } 188 | 189 | let mut permutator = Permutator::new(&input); 190 | let mut expected = expected[..].iter(); 191 | assert_eq!(&(permutator.nth(10).unwrap()), expected.nth(10).unwrap()); 192 | assert_eq!(&(permutator.nth(0).unwrap()), expected.nth(0).unwrap()); 193 | } 194 | 195 | fn get_input_d<'a>() -> [&'a [&'a i32]; 1] { 196 | [&[&1, &2, &3][..]] 197 | } 198 | 199 | fn get_expected_d<'a>() -> [&'a [&'a i32]; 27] { 200 | [ 201 | &[&1, &1, &1][..], 202 | &[&1, &1, &2][..], 203 | &[&1, &1, &3][..], 204 | &[&1, &2, &1][..], 205 | &[&1, &2, &2][..], 206 | &[&1, &2, &3][..], 207 | &[&1, &3, &1][..], 208 | &[&1, &3, &2][..], 209 | &[&1, &3, &3][..], 210 | &[&2, &1, &1][..], 211 | &[&2, &1, &2][..], 212 | &[&2, &1, &3][..], 213 | &[&2, &2, &1][..], 214 | &[&2, &2, &2][..], 215 | &[&2, &2, &3][..], 216 | &[&2, &3, &1][..], 217 | &[&2, &3, &2][..], 218 | &[&2, &3, &3][..], 219 | &[&3, &1, &1][..], 220 | &[&3, &1, &2][..], 221 | &[&3, &1, &3][..], 222 | &[&3, &2, &1][..], 223 | &[&3, &2, &2][..], 224 | &[&3, &2, &3][..], 225 | &[&3, &3, &1][..], 226 | &[&3, &3, &2][..], 227 | &[&3, &3, &3][..], 228 | ] 229 | } 230 | 231 | #[test] 232 | // Verify that the permutations are generated with the correct values, 233 | // in the correct order. 234 | fn test_value_permutation_b() { 235 | let input = get_input_d(); 236 | let expected = get_expected_d(); 237 | 238 | for (output, expected) in Permutator::, _>::new(&input).zip(expected[..].iter()) { 239 | assert_eq!(&output, expected); 240 | 241 | // also assert that for each value pair, both point to the same address 242 | for (o, e) in (*output).iter().zip(&expected[..]) { 243 | assert_eq!(*o as *const i32, *e as *const i32); 244 | } 245 | } 246 | 247 | let mut permutator = Permutator::new(&input); 248 | let mut expected = expected[..].iter(); 249 | assert_eq!(&(permutator.nth(10).unwrap()), expected.nth(10).unwrap()); 250 | assert_eq!(&(permutator.nth(0).unwrap()), expected.nth(0).unwrap()); 251 | } 252 | -------------------------------------------------------------------------------- /tests/todo.rs: -------------------------------------------------------------------------------- 1 | // test on an empty list 2 | // 3 | // { 4 | // empty list (panics on debug + creation) 5 | // let list: &[&bool] = &[]; 6 | // let list = [list; 1]; 7 | // let permutator = Permutator::new(&list); 8 | // // println!("{:#?}", &permutator); 9 | // for v in permutator { 10 | // println!("{:?}", &v); 11 | // } 12 | // } 13 | 14 | // use option specialization 15 | // 16 | // { 17 | // to use the option specialization (WIP) 18 | // let list: &[&bool] = &[]; 19 | // let list = [list; 1]; 20 | // let permutator: Permutator<_, Vec>> = Permutator::new(&list); 21 | // // println!("{:#?}", &permutator); 22 | // for v in permutator { 23 | // println!("{:?}", &v); 24 | // } 25 | // } 26 | -------------------------------------------------------------------------------- /tests/tuples.rs: -------------------------------------------------------------------------------- 1 | extern crate permutate; 2 | use permutate::{Permutator, PermutatorWrapper as _}; 3 | 4 | fn get_input<'a>() -> &'a (&'a [&'a str],) { 5 | &(&["A", "B", "C"],) 6 | } 7 | fn get_expected_a<'a>() -> [&'a (&'a str,); 3] { 8 | [&("A",), &("B",), &("C",)] 9 | } 10 | 11 | #[test] 12 | fn test_tuple_a() { 13 | let input = get_input().clone(); 14 | let expected = get_expected_a(); 15 | for (output, expected) in Permutator::new(&input).zip(expected[..].iter()) { 16 | assert_eq!(&output, *expected); 17 | 18 | // also assert that for each value pair, both point to the same address 19 | let (o, e) = (output.0, expected.0); 20 | assert_eq!(o as *const str, e as *const str); 21 | } 22 | } 23 | 24 | #[test] 25 | fn test_tuple_a_with_buffer() { 26 | let input = get_input().clone(); 27 | let expected = get_expected_a(); 28 | 29 | let mut permutator = Permutator::new(&input); 30 | let mut expected_iterator = expected[..].iter(); 31 | 32 | if let Some(mut permutation) = permutator.next() { 33 | let expected_permutation = expected_iterator.next().unwrap(); 34 | assert_eq!(&&permutation, expected_permutation); 35 | 36 | // also assert that for each value pair, both point to the same address 37 | let (o, e) = (permutation.0, expected_permutation.0); 38 | assert_eq!(o as *const str, e as *const str); 39 | 40 | while let Some(permutation) = permutator.next_with_buffer(&mut permutation) { 41 | let expected_permutation = expected_iterator.next().unwrap(); 42 | assert_eq!(&permutation, expected_permutation); 43 | 44 | // also assert that for each value pair, both point to the same address 45 | let (o, e) = (permutation.0, expected_permutation.0); 46 | assert_eq!(o as *const str, e as *const str); 47 | } 48 | } 49 | 50 | // verifies that the expected iterator has been fully consumed 51 | assert!(expected_iterator.next().is_none()) 52 | } 53 | 54 | fn get_input_b<'a>() -> &'a (&'a [&'a str], &'a [&'a i32]) { 55 | &(&["A", "B", "C"], &[&0, &1, &2]) 56 | } 57 | fn get_expected_b<'a>() -> [&'a (&'a str, &'a i32); 9] { 58 | [ 59 | &("A", &0), 60 | &("A", &1), 61 | &("A", &2), 62 | &("B", &0), 63 | &("B", &1), 64 | &("B", &2), 65 | &("C", &0), 66 | &("C", &1), 67 | &("C", &2), 68 | ] 69 | } 70 | 71 | #[test] 72 | fn test_tuple_b() { 73 | let input = get_input_b().clone(); 74 | let expected = get_expected_b(); 75 | for (output, expected) in Permutator::new(&input).zip(expected[..].iter()) { 76 | assert_eq!(&output, *expected); 77 | 78 | // also assert that for each value pair, both point to the same address 79 | let (o, e) = (output.0, expected.0); 80 | assert_eq!(o as *const str, e as *const str); 81 | let (o, e) = (output.1, expected.1); 82 | assert_eq!(o as *const i32, e as *const i32); 83 | } 84 | } 85 | 86 | #[test] 87 | fn test_tuple_b_with_buffer() { 88 | let input = get_input_b().clone(); 89 | let expected = get_expected_b(); 90 | 91 | let mut permutator = Permutator::new(&input); 92 | let mut expected_iterator = expected[..].iter(); 93 | 94 | if let Some(mut permutation) = permutator.next() { 95 | let expected_permutation = expected_iterator.next().unwrap(); 96 | assert_eq!(&&permutation, expected_permutation); 97 | 98 | // also assert that for each value pair, both point to the same address 99 | let (o, e) = (permutation.0, expected_permutation.0); 100 | assert_eq!(o as *const str, e as *const str); 101 | let (o, e) = (permutation.1, expected_permutation.1); 102 | assert_eq!(o as *const i32, e as *const i32); 103 | 104 | while let Some(permutation) = permutator.next_with_buffer(&mut permutation) { 105 | let expected_permutation = expected_iterator.next().unwrap(); 106 | assert_eq!(&permutation, expected_permutation); 107 | 108 | // also assert that for each value pair, both point to the same address 109 | let (o, e) = (permutation.0, expected_permutation.0); 110 | assert_eq!(o as *const str, e as *const str); 111 | let (o, e) = (permutation.1, expected_permutation.1); 112 | assert_eq!(o as *const i32, e as *const i32); 113 | } 114 | } 115 | 116 | // verifies that the expected iterator has been fully consumed 117 | assert!(expected_iterator.next().is_none()) 118 | } 119 | 120 | fn get_input_c<'a>() -> &'a (&'a [&'a str], &'a [&'a i32], &'a [&'a bool]) { 121 | &(&["A", "B"], &[&0, &1, &2], &[&false, &true]) 122 | } 123 | fn get_expected_c<'a>() -> [&'a (&'a str, &'a i32, &'a bool); 12] { 124 | [ 125 | &("A", &0, &false), 126 | &("A", &0, &true), 127 | &("A", &1, &false), 128 | &("A", &1, &true), 129 | &("A", &2, &false), 130 | &("A", &2, &true), 131 | &("B", &0, &false), 132 | &("B", &0, &true), 133 | &("B", &1, &false), 134 | &("B", &1, &true), 135 | &("B", &2, &false), 136 | &("B", &2, &true), 137 | ] 138 | } 139 | 140 | #[test] 141 | fn test_tuple_c() { 142 | let input = get_input_c().clone(); 143 | let expected = get_expected_c(); 144 | for (output, expected) in Permutator::new(&input).zip(expected[..].iter()) { 145 | assert_eq!(&output, *expected); 146 | 147 | // also assert that for each value pair, both point to the same address 148 | let (o, e) = (output.0, expected.0); 149 | assert_eq!(o as *const str, e as *const str); 150 | let (o, e) = (output.1, expected.1); 151 | assert_eq!(o as *const i32, e as *const i32); 152 | let (o, e) = (output.2, expected.2); 153 | assert_eq!(o as *const bool, e as *const bool); 154 | } 155 | } 156 | 157 | #[test] 158 | fn test_tuple_c_with_buffer() { 159 | let input = get_input_c().clone(); 160 | let expected = get_expected_c(); 161 | 162 | let mut permutator = Permutator::new(&input); 163 | let mut expected_iterator = expected[..].iter(); 164 | 165 | if let Some(mut permutation) = permutator.next() { 166 | let expected_permutation = expected_iterator.next().unwrap(); 167 | assert_eq!(&&permutation, expected_permutation); 168 | 169 | // also assert that for each value pair, both point to the same address 170 | let (o, e) = (permutation.0, expected_permutation.0); 171 | assert_eq!(o as *const str, e as *const str); 172 | let (o, e) = (permutation.1, expected_permutation.1); 173 | assert_eq!(o as *const i32, e as *const i32); 174 | let (o, e) = (permutation.2, expected_permutation.2); 175 | assert_eq!(o as *const bool, e as *const bool); 176 | 177 | while let Some(permutation) = permutator.next_with_buffer(&mut permutation) { 178 | let expected_permutation = expected_iterator.next().unwrap(); 179 | assert_eq!(&permutation, expected_permutation); 180 | 181 | // also assert that for each value pair, both point to the same address 182 | let (o, e) = (permutation.0, expected_permutation.0); 183 | assert_eq!(o as *const str, e as *const str); 184 | let (o, e) = (permutation.1, expected_permutation.1); 185 | assert_eq!(o as *const i32, e as *const i32); 186 | let (o, e) = (permutation.2, expected_permutation.2); 187 | assert_eq!(o as *const bool, e as *const bool); 188 | } 189 | } 190 | 191 | // verifies that the expected iterator has been fully consumed 192 | assert!(expected_iterator.next().is_none()) 193 | } 194 | 195 | fn get_input_d<'a>() -> &'a (&'a [&'a str], &'a [i32]) { 196 | &(&["A", "B"], &[0, 1]) 197 | } 198 | fn get_expected_d<'a>() -> [&'a (&'a str, i32); 4] { 199 | [&("A", 0), &("A", 1), &("B", 0), &("B", 1)] 200 | } 201 | 202 | #[test] 203 | fn test_tuple_d() { 204 | let input = get_input_d().clone(); 205 | let expected = get_expected_d(); 206 | for (output, expected) in Permutator::new(&input).zip(expected[..].iter()) { 207 | assert_eq!(&output, *expected); 208 | 209 | // also assert that for the first value pair, both point to the same address 210 | let (o, e) = (output.0, expected.0); 211 | assert_eq!(o as *const str, e as *const str); 212 | // and assert that for the second value pair, they have different addresses 213 | let (o, e) = (output.1, expected.1); 214 | assert!(&o as *const i32 != &e as *const i32); 215 | } 216 | } 217 | 218 | #[test] 219 | fn test_tuple_d_with_buffer() { 220 | let input = get_input_d().clone(); 221 | let expected = get_expected_d(); 222 | 223 | let mut permutator = Permutator::new(&input); 224 | let mut expected_iterator = expected[..].iter(); 225 | 226 | if let Some(mut permutation) = permutator.next() { 227 | let expected_permutation = expected_iterator.next().unwrap(); 228 | assert_eq!(&&permutation, expected_permutation); 229 | 230 | // also assert that for the first value pair, both point to the same address 231 | let (o, e) = (permutation.0, expected_permutation.0); 232 | assert_eq!(o as *const str, e as *const str); 233 | // and assert that for the second value pair, they have different addresses 234 | let (o, e) = (permutation.1, expected_permutation.1); 235 | assert!(&o as *const i32 != &e as *const i32); 236 | 237 | while let Some(permutation) = permutator.next_with_buffer(&mut permutation) { 238 | let expected_permutation = expected_iterator.next().unwrap(); 239 | assert_eq!(&permutation, expected_permutation); 240 | 241 | // also assert that for the first value pair, both point to the same address 242 | let (o, e) = (permutation.0, expected_permutation.0); 243 | assert_eq!(o as *const str, e as *const str); 244 | // and assert that for the second value pair, they have different addresses 245 | let (o, e) = (permutation.1, expected_permutation.1); 246 | assert!(&o as *const i32 != &e as *const i32) 247 | } 248 | } 249 | 250 | // verifies that the expected iterator has been fully consumed 251 | assert!(expected_iterator.next().is_none()) 252 | } 253 | --------------------------------------------------------------------------------