├── .gitattributes ├── .gitignore ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── README.md ├── benches.ipynb ├── benches └── against-nonempty.rs ├── gen ├── Cargo.toml └── src │ └── main.rs ├── src ├── arbitrary1.rs ├── array.rs ├── iter.rs ├── lib.rs ├── mirror_std │ ├── cmp.rs │ ├── from.rs │ ├── partial_eq.rs │ └── try_from.rs ├── proptest1.rs ├── quickcheck1.rs ├── schemars08.rs ├── serde1.rs ├── slice.rs └── vec.rs └── tests ├── from.rs ├── partial_eq.rs └── try_from.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | *.ipynb linguist-generated=true 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.features": "all" 3 | } 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "getrandom", 28 | "once_cell", 29 | "version_check", 30 | "zerocopy", 31 | ] 32 | 33 | [[package]] 34 | name = "aho-corasick" 35 | version = "1.1.3" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 38 | dependencies = [ 39 | "memchr", 40 | ] 41 | 42 | [[package]] 43 | name = "anstream" 44 | version = "0.6.13" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" 47 | dependencies = [ 48 | "anstyle", 49 | "anstyle-parse", 50 | "anstyle-query", 51 | "anstyle-wincon", 52 | "colorchoice", 53 | "utf8parse", 54 | ] 55 | 56 | [[package]] 57 | name = "anstyle" 58 | version = "1.0.6" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" 61 | 62 | [[package]] 63 | name = "anstyle-parse" 64 | version = "0.2.3" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 67 | dependencies = [ 68 | "utf8parse", 69 | ] 70 | 71 | [[package]] 72 | name = "anstyle-query" 73 | version = "1.0.2" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" 76 | dependencies = [ 77 | "windows-sys 0.52.0", 78 | ] 79 | 80 | [[package]] 81 | name = "anstyle-wincon" 82 | version = "3.0.2" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 85 | dependencies = [ 86 | "anstyle", 87 | "windows-sys 0.52.0", 88 | ] 89 | 90 | [[package]] 91 | name = "anyhow" 92 | version = "1.0.82" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" 95 | 96 | [[package]] 97 | name = "arbitrary" 98 | version = "1.3.2" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" 101 | 102 | [[package]] 103 | name = "autocfg" 104 | version = "1.2.0" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" 107 | 108 | [[package]] 109 | name = "backtrace" 110 | version = "0.3.71" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" 113 | dependencies = [ 114 | "addr2line", 115 | "cc", 116 | "cfg-if", 117 | "libc", 118 | "miniz_oxide", 119 | "object", 120 | "rustc-demangle", 121 | ] 122 | 123 | [[package]] 124 | name = "backtrace-ext" 125 | version = "0.2.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" 128 | dependencies = [ 129 | "backtrace", 130 | ] 131 | 132 | [[package]] 133 | name = "base64" 134 | version = "0.21.7" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 137 | 138 | [[package]] 139 | name = "bit-set" 140 | version = "0.5.3" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" 143 | dependencies = [ 144 | "bit-vec", 145 | ] 146 | 147 | [[package]] 148 | name = "bit-vec" 149 | version = "0.6.3" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 152 | 153 | [[package]] 154 | name = "bitflags" 155 | version = "1.3.2" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 158 | 159 | [[package]] 160 | name = "bitflags" 161 | version = "2.5.0" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 164 | 165 | [[package]] 166 | name = "byteorder" 167 | version = "1.5.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 170 | 171 | [[package]] 172 | name = "cc" 173 | version = "1.0.95" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" 176 | 177 | [[package]] 178 | name = "cfg-if" 179 | version = "1.0.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 182 | 183 | [[package]] 184 | name = "clap" 185 | version = "4.5.4" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" 188 | dependencies = [ 189 | "clap_builder", 190 | "clap_derive", 191 | ] 192 | 193 | [[package]] 194 | name = "clap_builder" 195 | version = "4.5.2" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" 198 | dependencies = [ 199 | "anstream", 200 | "anstyle", 201 | "clap_lex", 202 | "strsim", 203 | "terminal_size", 204 | ] 205 | 206 | [[package]] 207 | name = "clap_derive" 208 | version = "4.5.4" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" 211 | dependencies = [ 212 | "heck", 213 | "proc-macro2", 214 | "quote", 215 | "syn 2.0.60", 216 | ] 217 | 218 | [[package]] 219 | name = "clap_lex" 220 | version = "0.7.0" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" 223 | 224 | [[package]] 225 | name = "colorchoice" 226 | version = "1.0.0" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 229 | 230 | [[package]] 231 | name = "condtype" 232 | version = "1.3.0" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" 235 | 236 | [[package]] 237 | name = "crc32fast" 238 | version = "1.4.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" 241 | dependencies = [ 242 | "cfg-if", 243 | ] 244 | 245 | [[package]] 246 | name = "cssparser" 247 | version = "0.31.2" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be" 250 | dependencies = [ 251 | "cssparser-macros", 252 | "dtoa-short", 253 | "itoa", 254 | "phf 0.11.2", 255 | "smallvec", 256 | ] 257 | 258 | [[package]] 259 | name = "cssparser-macros" 260 | version = "0.6.1" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" 263 | dependencies = [ 264 | "quote", 265 | "syn 2.0.60", 266 | ] 267 | 268 | [[package]] 269 | name = "derive_more" 270 | version = "0.99.17" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" 273 | dependencies = [ 274 | "proc-macro2", 275 | "quote", 276 | "syn 1.0.109", 277 | ] 278 | 279 | [[package]] 280 | name = "divan" 281 | version = "0.1.14" 282 | source = "git+https://github.com/OliverKillane/divan?branch=enh/file-output#c54ac74a8b85e3862a4bcbaea9e08d9e5095caa5" 283 | dependencies = [ 284 | "cfg-if", 285 | "clap", 286 | "condtype", 287 | "divan-macros", 288 | "libc", 289 | "regex-lite", 290 | "serde_json", 291 | ] 292 | 293 | [[package]] 294 | name = "divan-macros" 295 | version = "0.1.14" 296 | source = "git+https://github.com/OliverKillane/divan?branch=enh/file-output#c54ac74a8b85e3862a4bcbaea9e08d9e5095caa5" 297 | dependencies = [ 298 | "proc-macro2", 299 | "quote", 300 | "syn 2.0.60", 301 | ] 302 | 303 | [[package]] 304 | name = "dtoa" 305 | version = "1.0.9" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" 308 | 309 | [[package]] 310 | name = "dtoa-short" 311 | version = "0.3.4" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" 314 | dependencies = [ 315 | "dtoa", 316 | ] 317 | 318 | [[package]] 319 | name = "dyn-clone" 320 | version = "1.0.17" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" 323 | 324 | [[package]] 325 | name = "ego-tree" 326 | version = "0.6.2" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" 329 | 330 | [[package]] 331 | name = "errno" 332 | version = "0.3.8" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 335 | dependencies = [ 336 | "libc", 337 | "windows-sys 0.52.0", 338 | ] 339 | 340 | [[package]] 341 | name = "fastrand" 342 | version = "2.0.2" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" 345 | 346 | [[package]] 347 | name = "flate2" 348 | version = "1.0.28" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" 351 | dependencies = [ 352 | "crc32fast", 353 | "miniz_oxide", 354 | ] 355 | 356 | [[package]] 357 | name = "fnv" 358 | version = "1.0.7" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 361 | 362 | [[package]] 363 | name = "form_urlencoded" 364 | version = "1.2.1" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 367 | dependencies = [ 368 | "percent-encoding", 369 | ] 370 | 371 | [[package]] 372 | name = "futf" 373 | version = "0.1.5" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" 376 | dependencies = [ 377 | "mac", 378 | "new_debug_unreachable", 379 | ] 380 | 381 | [[package]] 382 | name = "fxhash" 383 | version = "0.2.1" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 386 | dependencies = [ 387 | "byteorder", 388 | ] 389 | 390 | [[package]] 391 | name = "gen" 392 | version = "0.0.0" 393 | dependencies = [ 394 | "anyhow", 395 | "clap", 396 | "owo-colors", 397 | "prettyplease", 398 | "proc-macro2", 399 | "quote", 400 | "regex", 401 | "scraper", 402 | "syn 2.0.60", 403 | "syn-miette", 404 | "ureq", 405 | ] 406 | 407 | [[package]] 408 | name = "getopts" 409 | version = "0.2.21" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" 412 | dependencies = [ 413 | "unicode-width", 414 | ] 415 | 416 | [[package]] 417 | name = "getrandom" 418 | version = "0.2.14" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" 421 | dependencies = [ 422 | "cfg-if", 423 | "libc", 424 | "wasi", 425 | ] 426 | 427 | [[package]] 428 | name = "gimli" 429 | version = "0.28.1" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 432 | 433 | [[package]] 434 | name = "heck" 435 | version = "0.5.0" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 438 | 439 | [[package]] 440 | name = "html5ever" 441 | version = "0.26.0" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" 444 | dependencies = [ 445 | "log", 446 | "mac", 447 | "markup5ever", 448 | "proc-macro2", 449 | "quote", 450 | "syn 1.0.109", 451 | ] 452 | 453 | [[package]] 454 | name = "idna" 455 | version = "0.5.0" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 458 | dependencies = [ 459 | "unicode-bidi", 460 | "unicode-normalization", 461 | ] 462 | 463 | [[package]] 464 | name = "is_ci" 465 | version = "1.2.0" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" 468 | 469 | [[package]] 470 | name = "itoa" 471 | version = "1.0.11" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 474 | 475 | [[package]] 476 | name = "lazy_static" 477 | version = "1.4.0" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 480 | 481 | [[package]] 482 | name = "libc" 483 | version = "0.2.153" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 486 | 487 | [[package]] 488 | name = "libm" 489 | version = "0.2.8" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" 492 | 493 | [[package]] 494 | name = "linux-raw-sys" 495 | version = "0.4.13" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 498 | 499 | [[package]] 500 | name = "lock_api" 501 | version = "0.4.11" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 504 | dependencies = [ 505 | "autocfg", 506 | "scopeguard", 507 | ] 508 | 509 | [[package]] 510 | name = "log" 511 | version = "0.4.21" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 514 | 515 | [[package]] 516 | name = "mac" 517 | version = "0.1.1" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 520 | 521 | [[package]] 522 | name = "markup5ever" 523 | version = "0.11.0" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" 526 | dependencies = [ 527 | "log", 528 | "phf 0.10.1", 529 | "phf_codegen", 530 | "string_cache", 531 | "string_cache_codegen", 532 | "tendril", 533 | ] 534 | 535 | [[package]] 536 | name = "memchr" 537 | version = "2.7.2" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" 540 | 541 | [[package]] 542 | name = "miette" 543 | version = "7.2.0" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1" 546 | dependencies = [ 547 | "backtrace", 548 | "backtrace-ext", 549 | "cfg-if", 550 | "miette-derive", 551 | "owo-colors", 552 | "supports-color", 553 | "supports-hyperlinks", 554 | "supports-unicode", 555 | "terminal_size", 556 | "textwrap", 557 | "thiserror", 558 | "unicode-width", 559 | ] 560 | 561 | [[package]] 562 | name = "miette-derive" 563 | version = "7.2.0" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" 566 | dependencies = [ 567 | "proc-macro2", 568 | "quote", 569 | "syn 2.0.60", 570 | ] 571 | 572 | [[package]] 573 | name = "miniz_oxide" 574 | version = "0.7.2" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" 577 | dependencies = [ 578 | "adler", 579 | ] 580 | 581 | [[package]] 582 | name = "new_debug_unreachable" 583 | version = "1.0.6" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 586 | 587 | [[package]] 588 | name = "nonempty" 589 | version = "0.10.0" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "303e8749c804ccd6ca3b428de7fe0d86cb86bc7606bc15291f100fd487960bb8" 592 | 593 | [[package]] 594 | name = "num-traits" 595 | version = "0.2.18" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" 598 | dependencies = [ 599 | "autocfg", 600 | "libm", 601 | ] 602 | 603 | [[package]] 604 | name = "nunny" 605 | version = "0.2.1" 606 | dependencies = [ 607 | "arbitrary", 608 | "divan", 609 | "nonempty", 610 | "proptest", 611 | "quickcheck", 612 | "schemars", 613 | "serde", 614 | ] 615 | 616 | [[package]] 617 | name = "object" 618 | version = "0.32.2" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 621 | dependencies = [ 622 | "memchr", 623 | ] 624 | 625 | [[package]] 626 | name = "once_cell" 627 | version = "1.19.0" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 630 | 631 | [[package]] 632 | name = "owo-colors" 633 | version = "4.0.0" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" 636 | 637 | [[package]] 638 | name = "parking_lot" 639 | version = "0.12.1" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 642 | dependencies = [ 643 | "lock_api", 644 | "parking_lot_core", 645 | ] 646 | 647 | [[package]] 648 | name = "parking_lot_core" 649 | version = "0.9.9" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" 652 | dependencies = [ 653 | "cfg-if", 654 | "libc", 655 | "redox_syscall", 656 | "smallvec", 657 | "windows-targets 0.48.5", 658 | ] 659 | 660 | [[package]] 661 | name = "percent-encoding" 662 | version = "2.3.1" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 665 | 666 | [[package]] 667 | name = "phf" 668 | version = "0.10.1" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" 671 | dependencies = [ 672 | "phf_shared 0.10.0", 673 | ] 674 | 675 | [[package]] 676 | name = "phf" 677 | version = "0.11.2" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" 680 | dependencies = [ 681 | "phf_macros", 682 | "phf_shared 0.11.2", 683 | ] 684 | 685 | [[package]] 686 | name = "phf_codegen" 687 | version = "0.10.0" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" 690 | dependencies = [ 691 | "phf_generator 0.10.0", 692 | "phf_shared 0.10.0", 693 | ] 694 | 695 | [[package]] 696 | name = "phf_generator" 697 | version = "0.10.0" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" 700 | dependencies = [ 701 | "phf_shared 0.10.0", 702 | "rand", 703 | ] 704 | 705 | [[package]] 706 | name = "phf_generator" 707 | version = "0.11.2" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" 710 | dependencies = [ 711 | "phf_shared 0.11.2", 712 | "rand", 713 | ] 714 | 715 | [[package]] 716 | name = "phf_macros" 717 | version = "0.11.2" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" 720 | dependencies = [ 721 | "phf_generator 0.11.2", 722 | "phf_shared 0.11.2", 723 | "proc-macro2", 724 | "quote", 725 | "syn 2.0.60", 726 | ] 727 | 728 | [[package]] 729 | name = "phf_shared" 730 | version = "0.10.0" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 733 | dependencies = [ 734 | "siphasher", 735 | ] 736 | 737 | [[package]] 738 | name = "phf_shared" 739 | version = "0.11.2" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" 742 | dependencies = [ 743 | "siphasher", 744 | ] 745 | 746 | [[package]] 747 | name = "ppv-lite86" 748 | version = "0.2.17" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 751 | 752 | [[package]] 753 | name = "precomputed-hash" 754 | version = "0.1.1" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 757 | 758 | [[package]] 759 | name = "prettyplease" 760 | version = "0.2.19" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550" 763 | dependencies = [ 764 | "proc-macro2", 765 | "syn 2.0.60", 766 | ] 767 | 768 | [[package]] 769 | name = "proc-macro2" 770 | version = "1.0.81" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" 773 | dependencies = [ 774 | "unicode-ident", 775 | ] 776 | 777 | [[package]] 778 | name = "proptest" 779 | version = "1.4.0" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" 782 | dependencies = [ 783 | "bit-set", 784 | "bit-vec", 785 | "bitflags 2.5.0", 786 | "lazy_static", 787 | "num-traits", 788 | "rand", 789 | "rand_chacha", 790 | "rand_xorshift", 791 | "regex-syntax", 792 | "rusty-fork", 793 | "tempfile", 794 | "unarray", 795 | ] 796 | 797 | [[package]] 798 | name = "quick-error" 799 | version = "1.2.3" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 802 | 803 | [[package]] 804 | name = "quickcheck" 805 | version = "1.0.3" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" 808 | dependencies = [ 809 | "rand", 810 | ] 811 | 812 | [[package]] 813 | name = "quote" 814 | version = "1.0.36" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 817 | dependencies = [ 818 | "proc-macro2", 819 | ] 820 | 821 | [[package]] 822 | name = "rand" 823 | version = "0.8.5" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 826 | dependencies = [ 827 | "libc", 828 | "rand_chacha", 829 | "rand_core", 830 | ] 831 | 832 | [[package]] 833 | name = "rand_chacha" 834 | version = "0.3.1" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 837 | dependencies = [ 838 | "ppv-lite86", 839 | "rand_core", 840 | ] 841 | 842 | [[package]] 843 | name = "rand_core" 844 | version = "0.6.4" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 847 | dependencies = [ 848 | "getrandom", 849 | ] 850 | 851 | [[package]] 852 | name = "rand_xorshift" 853 | version = "0.3.0" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" 856 | dependencies = [ 857 | "rand_core", 858 | ] 859 | 860 | [[package]] 861 | name = "redox_syscall" 862 | version = "0.4.1" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 865 | dependencies = [ 866 | "bitflags 1.3.2", 867 | ] 868 | 869 | [[package]] 870 | name = "regex" 871 | version = "1.10.4" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" 874 | dependencies = [ 875 | "aho-corasick", 876 | "memchr", 877 | "regex-automata", 878 | "regex-syntax", 879 | ] 880 | 881 | [[package]] 882 | name = "regex-automata" 883 | version = "0.4.6" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" 886 | dependencies = [ 887 | "aho-corasick", 888 | "memchr", 889 | "regex-syntax", 890 | ] 891 | 892 | [[package]] 893 | name = "regex-lite" 894 | version = "0.1.5" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" 897 | 898 | [[package]] 899 | name = "regex-syntax" 900 | version = "0.8.3" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" 903 | 904 | [[package]] 905 | name = "ring" 906 | version = "0.17.8" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 909 | dependencies = [ 910 | "cc", 911 | "cfg-if", 912 | "getrandom", 913 | "libc", 914 | "spin", 915 | "untrusted", 916 | "windows-sys 0.52.0", 917 | ] 918 | 919 | [[package]] 920 | name = "rustc-demangle" 921 | version = "0.1.23" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 924 | 925 | [[package]] 926 | name = "rustix" 927 | version = "0.38.34" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 930 | dependencies = [ 931 | "bitflags 2.5.0", 932 | "errno", 933 | "libc", 934 | "linux-raw-sys", 935 | "windows-sys 0.52.0", 936 | ] 937 | 938 | [[package]] 939 | name = "rustls" 940 | version = "0.22.4" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" 943 | dependencies = [ 944 | "log", 945 | "ring", 946 | "rustls-pki-types", 947 | "rustls-webpki", 948 | "subtle", 949 | "zeroize", 950 | ] 951 | 952 | [[package]] 953 | name = "rustls-pki-types" 954 | version = "1.5.0" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" 957 | 958 | [[package]] 959 | name = "rustls-webpki" 960 | version = "0.102.3" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" 963 | dependencies = [ 964 | "ring", 965 | "rustls-pki-types", 966 | "untrusted", 967 | ] 968 | 969 | [[package]] 970 | name = "rusty-fork" 971 | version = "0.3.0" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" 974 | dependencies = [ 975 | "fnv", 976 | "quick-error", 977 | "tempfile", 978 | "wait-timeout", 979 | ] 980 | 981 | [[package]] 982 | name = "ryu" 983 | version = "1.0.17" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 986 | 987 | [[package]] 988 | name = "schemars" 989 | version = "0.8.16" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" 992 | dependencies = [ 993 | "dyn-clone", 994 | "serde", 995 | "serde_json", 996 | ] 997 | 998 | [[package]] 999 | name = "scopeguard" 1000 | version = "1.2.0" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1003 | 1004 | [[package]] 1005 | name = "scraper" 1006 | version = "0.19.0" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | checksum = "5b80b33679ff7a0ea53d37f3b39de77ea0c75b12c5805ac43ec0c33b3051af1b" 1009 | dependencies = [ 1010 | "ahash", 1011 | "cssparser", 1012 | "ego-tree", 1013 | "getopts", 1014 | "html5ever", 1015 | "once_cell", 1016 | "selectors", 1017 | "tendril", 1018 | ] 1019 | 1020 | [[package]] 1021 | name = "selectors" 1022 | version = "0.25.0" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" 1025 | dependencies = [ 1026 | "bitflags 2.5.0", 1027 | "cssparser", 1028 | "derive_more", 1029 | "fxhash", 1030 | "log", 1031 | "new_debug_unreachable", 1032 | "phf 0.10.1", 1033 | "phf_codegen", 1034 | "precomputed-hash", 1035 | "servo_arc", 1036 | "smallvec", 1037 | ] 1038 | 1039 | [[package]] 1040 | name = "serde" 1041 | version = "1.0.198" 1042 | source = "registry+https://github.com/rust-lang/crates.io-index" 1043 | checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" 1044 | dependencies = [ 1045 | "serde_derive", 1046 | ] 1047 | 1048 | [[package]] 1049 | name = "serde_derive" 1050 | version = "1.0.198" 1051 | source = "registry+https://github.com/rust-lang/crates.io-index" 1052 | checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" 1053 | dependencies = [ 1054 | "proc-macro2", 1055 | "quote", 1056 | "syn 2.0.60", 1057 | ] 1058 | 1059 | [[package]] 1060 | name = "serde_json" 1061 | version = "1.0.116" 1062 | source = "registry+https://github.com/rust-lang/crates.io-index" 1063 | checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" 1064 | dependencies = [ 1065 | "itoa", 1066 | "ryu", 1067 | "serde", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "servo_arc" 1072 | version = "0.3.0" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" 1075 | dependencies = [ 1076 | "stable_deref_trait", 1077 | ] 1078 | 1079 | [[package]] 1080 | name = "siphasher" 1081 | version = "0.3.11" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 1084 | 1085 | [[package]] 1086 | name = "smallvec" 1087 | version = "1.13.2" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1090 | 1091 | [[package]] 1092 | name = "smawk" 1093 | version = "0.3.2" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" 1096 | 1097 | [[package]] 1098 | name = "spin" 1099 | version = "0.9.8" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1102 | 1103 | [[package]] 1104 | name = "stable_deref_trait" 1105 | version = "1.2.0" 1106 | source = "registry+https://github.com/rust-lang/crates.io-index" 1107 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1108 | 1109 | [[package]] 1110 | name = "string_cache" 1111 | version = "0.8.7" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" 1114 | dependencies = [ 1115 | "new_debug_unreachable", 1116 | "once_cell", 1117 | "parking_lot", 1118 | "phf_shared 0.10.0", 1119 | "precomputed-hash", 1120 | "serde", 1121 | ] 1122 | 1123 | [[package]] 1124 | name = "string_cache_codegen" 1125 | version = "0.5.2" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" 1128 | dependencies = [ 1129 | "phf_generator 0.10.0", 1130 | "phf_shared 0.10.0", 1131 | "proc-macro2", 1132 | "quote", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "strsim" 1137 | version = "0.11.1" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1140 | 1141 | [[package]] 1142 | name = "subtle" 1143 | version = "2.5.0" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 1146 | 1147 | [[package]] 1148 | name = "supports-color" 1149 | version = "3.0.0" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "9829b314621dfc575df4e409e79f9d6a66a3bd707ab73f23cb4aa3a854ac854f" 1152 | dependencies = [ 1153 | "is_ci", 1154 | ] 1155 | 1156 | [[package]] 1157 | name = "supports-hyperlinks" 1158 | version = "3.0.0" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "2c0a1e5168041f5f3ff68ff7d95dcb9c8749df29f6e7e89ada40dd4c9de404ee" 1161 | 1162 | [[package]] 1163 | name = "supports-unicode" 1164 | version = "3.0.0" 1165 | source = "registry+https://github.com/rust-lang/crates.io-index" 1166 | checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" 1167 | 1168 | [[package]] 1169 | name = "syn" 1170 | version = "1.0.109" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1173 | dependencies = [ 1174 | "proc-macro2", 1175 | "quote", 1176 | "unicode-ident", 1177 | ] 1178 | 1179 | [[package]] 1180 | name = "syn" 1181 | version = "2.0.60" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" 1184 | dependencies = [ 1185 | "proc-macro2", 1186 | "quote", 1187 | "unicode-ident", 1188 | ] 1189 | 1190 | [[package]] 1191 | name = "syn-miette" 1192 | version = "0.3.0" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "dd1a2bfae2df81406f8d21baa0253d34ddd0ddafcd1e7aa12aa24279bb76a24b" 1195 | dependencies = [ 1196 | "miette", 1197 | "proc-macro2", 1198 | "syn 2.0.60", 1199 | ] 1200 | 1201 | [[package]] 1202 | name = "tempfile" 1203 | version = "3.10.1" 1204 | source = "registry+https://github.com/rust-lang/crates.io-index" 1205 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 1206 | dependencies = [ 1207 | "cfg-if", 1208 | "fastrand", 1209 | "rustix", 1210 | "windows-sys 0.52.0", 1211 | ] 1212 | 1213 | [[package]] 1214 | name = "tendril" 1215 | version = "0.4.3" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" 1218 | dependencies = [ 1219 | "futf", 1220 | "mac", 1221 | "utf-8", 1222 | ] 1223 | 1224 | [[package]] 1225 | name = "terminal_size" 1226 | version = "0.3.0" 1227 | source = "registry+https://github.com/rust-lang/crates.io-index" 1228 | checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" 1229 | dependencies = [ 1230 | "rustix", 1231 | "windows-sys 0.48.0", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "textwrap" 1236 | version = "0.16.1" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" 1239 | dependencies = [ 1240 | "smawk", 1241 | "unicode-linebreak", 1242 | "unicode-width", 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "thiserror" 1247 | version = "1.0.59" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" 1250 | dependencies = [ 1251 | "thiserror-impl", 1252 | ] 1253 | 1254 | [[package]] 1255 | name = "thiserror-impl" 1256 | version = "1.0.59" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" 1259 | dependencies = [ 1260 | "proc-macro2", 1261 | "quote", 1262 | "syn 2.0.60", 1263 | ] 1264 | 1265 | [[package]] 1266 | name = "tinyvec" 1267 | version = "1.6.0" 1268 | source = "registry+https://github.com/rust-lang/crates.io-index" 1269 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1270 | dependencies = [ 1271 | "tinyvec_macros", 1272 | ] 1273 | 1274 | [[package]] 1275 | name = "tinyvec_macros" 1276 | version = "0.1.1" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1279 | 1280 | [[package]] 1281 | name = "unarray" 1282 | version = "0.1.4" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" 1285 | 1286 | [[package]] 1287 | name = "unicode-bidi" 1288 | version = "0.3.15" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 1291 | 1292 | [[package]] 1293 | name = "unicode-ident" 1294 | version = "1.0.12" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1297 | 1298 | [[package]] 1299 | name = "unicode-linebreak" 1300 | version = "0.1.5" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" 1303 | 1304 | [[package]] 1305 | name = "unicode-normalization" 1306 | version = "0.1.23" 1307 | source = "registry+https://github.com/rust-lang/crates.io-index" 1308 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 1309 | dependencies = [ 1310 | "tinyvec", 1311 | ] 1312 | 1313 | [[package]] 1314 | name = "unicode-width" 1315 | version = "0.1.11" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" 1318 | 1319 | [[package]] 1320 | name = "untrusted" 1321 | version = "0.9.0" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1324 | 1325 | [[package]] 1326 | name = "ureq" 1327 | version = "2.9.6" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" 1330 | dependencies = [ 1331 | "base64", 1332 | "flate2", 1333 | "log", 1334 | "once_cell", 1335 | "rustls", 1336 | "rustls-pki-types", 1337 | "rustls-webpki", 1338 | "url", 1339 | "webpki-roots", 1340 | ] 1341 | 1342 | [[package]] 1343 | name = "url" 1344 | version = "2.5.0" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 1347 | dependencies = [ 1348 | "form_urlencoded", 1349 | "idna", 1350 | "percent-encoding", 1351 | ] 1352 | 1353 | [[package]] 1354 | name = "utf-8" 1355 | version = "0.7.6" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1358 | 1359 | [[package]] 1360 | name = "utf8parse" 1361 | version = "0.2.1" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 1364 | 1365 | [[package]] 1366 | name = "version_check" 1367 | version = "0.9.4" 1368 | source = "registry+https://github.com/rust-lang/crates.io-index" 1369 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1370 | 1371 | [[package]] 1372 | name = "wait-timeout" 1373 | version = "0.2.0" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" 1376 | dependencies = [ 1377 | "libc", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "wasi" 1382 | version = "0.11.0+wasi-snapshot-preview1" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1385 | 1386 | [[package]] 1387 | name = "webpki-roots" 1388 | version = "0.26.1" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" 1391 | dependencies = [ 1392 | "rustls-pki-types", 1393 | ] 1394 | 1395 | [[package]] 1396 | name = "windows-sys" 1397 | version = "0.48.0" 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" 1399 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1400 | dependencies = [ 1401 | "windows-targets 0.48.5", 1402 | ] 1403 | 1404 | [[package]] 1405 | name = "windows-sys" 1406 | version = "0.52.0" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1409 | dependencies = [ 1410 | "windows-targets 0.52.5", 1411 | ] 1412 | 1413 | [[package]] 1414 | name = "windows-targets" 1415 | version = "0.48.5" 1416 | source = "registry+https://github.com/rust-lang/crates.io-index" 1417 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 1418 | dependencies = [ 1419 | "windows_aarch64_gnullvm 0.48.5", 1420 | "windows_aarch64_msvc 0.48.5", 1421 | "windows_i686_gnu 0.48.5", 1422 | "windows_i686_msvc 0.48.5", 1423 | "windows_x86_64_gnu 0.48.5", 1424 | "windows_x86_64_gnullvm 0.48.5", 1425 | "windows_x86_64_msvc 0.48.5", 1426 | ] 1427 | 1428 | [[package]] 1429 | name = "windows-targets" 1430 | version = "0.52.5" 1431 | source = "registry+https://github.com/rust-lang/crates.io-index" 1432 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 1433 | dependencies = [ 1434 | "windows_aarch64_gnullvm 0.52.5", 1435 | "windows_aarch64_msvc 0.52.5", 1436 | "windows_i686_gnu 0.52.5", 1437 | "windows_i686_gnullvm", 1438 | "windows_i686_msvc 0.52.5", 1439 | "windows_x86_64_gnu 0.52.5", 1440 | "windows_x86_64_gnullvm 0.52.5", 1441 | "windows_x86_64_msvc 0.52.5", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "windows_aarch64_gnullvm" 1446 | version = "0.48.5" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1449 | 1450 | [[package]] 1451 | name = "windows_aarch64_gnullvm" 1452 | version = "0.52.5" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 1455 | 1456 | [[package]] 1457 | name = "windows_aarch64_msvc" 1458 | version = "0.48.5" 1459 | source = "registry+https://github.com/rust-lang/crates.io-index" 1460 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1461 | 1462 | [[package]] 1463 | name = "windows_aarch64_msvc" 1464 | version = "0.52.5" 1465 | source = "registry+https://github.com/rust-lang/crates.io-index" 1466 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 1467 | 1468 | [[package]] 1469 | name = "windows_i686_gnu" 1470 | version = "0.48.5" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1473 | 1474 | [[package]] 1475 | name = "windows_i686_gnu" 1476 | version = "0.52.5" 1477 | source = "registry+https://github.com/rust-lang/crates.io-index" 1478 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 1479 | 1480 | [[package]] 1481 | name = "windows_i686_gnullvm" 1482 | version = "0.52.5" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 1485 | 1486 | [[package]] 1487 | name = "windows_i686_msvc" 1488 | version = "0.48.5" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1491 | 1492 | [[package]] 1493 | name = "windows_i686_msvc" 1494 | version = "0.52.5" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 1497 | 1498 | [[package]] 1499 | name = "windows_x86_64_gnu" 1500 | version = "0.48.5" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1503 | 1504 | [[package]] 1505 | name = "windows_x86_64_gnu" 1506 | version = "0.52.5" 1507 | source = "registry+https://github.com/rust-lang/crates.io-index" 1508 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 1509 | 1510 | [[package]] 1511 | name = "windows_x86_64_gnullvm" 1512 | version = "0.48.5" 1513 | source = "registry+https://github.com/rust-lang/crates.io-index" 1514 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1515 | 1516 | [[package]] 1517 | name = "windows_x86_64_gnullvm" 1518 | version = "0.52.5" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 1521 | 1522 | [[package]] 1523 | name = "windows_x86_64_msvc" 1524 | version = "0.48.5" 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" 1526 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1527 | 1528 | [[package]] 1529 | name = "windows_x86_64_msvc" 1530 | version = "0.52.5" 1531 | source = "registry+https://github.com/rust-lang/crates.io-index" 1532 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 1533 | 1534 | [[package]] 1535 | name = "zerocopy" 1536 | version = "0.7.32" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" 1539 | dependencies = [ 1540 | "zerocopy-derive", 1541 | ] 1542 | 1543 | [[package]] 1544 | name = "zerocopy-derive" 1545 | version = "0.7.32" 1546 | source = "registry+https://github.com/rust-lang/crates.io-index" 1547 | checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" 1548 | dependencies = [ 1549 | "proc-macro2", 1550 | "quote", 1551 | "syn 2.0.60", 1552 | ] 1553 | 1554 | [[package]] 1555 | name = "zeroize" 1556 | version = "1.7.0" 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" 1558 | checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" 1559 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nunny" 3 | version = "0.2.1" 4 | edition = "2021" 5 | description = "the definitive non-empty slice/array/vec library for Rust" 6 | license = "MIT OR Apache-2.0" 7 | homepage = "https://crates.io/nunny" 8 | documentation = "https://docs.rs/nunny" 9 | repository = "https://github.com/aatifsyed/nunny" 10 | categories = [ 11 | "rust-patterns", 12 | "no-std", 13 | "memory-management", 14 | "embedded", 15 | "data-structures", 16 | ] 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["alloc", "serde1/std"] 21 | alloc = ["serde1?/alloc"] 22 | # This feature will always track the latest (API) version of serde. 23 | # Changing it to `serde2` is not considered a breaking change 24 | serde = ["serde1"] 25 | serde1 = ["dep:serde1"] 26 | # This feature will always track the latest (API) version of arbitrary. 27 | # Changing it to `arbitrary2` is not considered a breaking change 28 | arbitrary = ["arbitrary1"] 29 | arbitrary1 = ["dep:arbitrary1", "std"] 30 | # This feature will always track the latest (API) version of quickcheck. 31 | # Changing it to `quickcheck2` is not considered a breaking change 32 | quickcheck = ["quickcheck1"] 33 | quickcheck1 = ["dep:quickcheck1", "std"] 34 | # This feature will always track the latest (API) version of proptest. 35 | # Changing it to `proptest2` is not considered a breaking change 36 | # proptest has a `std` and `alloc` feature, but trying --no-default-features with them broke... 37 | proptest = ["proptest1"] 38 | proptest1 = ["dep:proptest1", "std"] 39 | # This feature will always track the latest (API) version of schemars. 40 | # Changing it to `schemars09` is not considered a breaking change 41 | schemars = ["schemars08"] 42 | schemars08 = ["dep:schemars08", "std"] 43 | 44 | [dependencies] 45 | proptest1 = { version = "1.4.0", package = "proptest", optional = true } 46 | arbitrary1 = { version = "1.3.2", package = "arbitrary", optional = true } 47 | quickcheck1 = { version = "1.0.3", package = "quickcheck", optional = true, default-features = false } 48 | serde1 = { version = "1.0.198", package = "serde", optional = true, default-features = false } 49 | schemars08 = { version = "0.8.16", package = "schemars", optional = true, default-features = false } 50 | 51 | [workspace] 52 | members = ["gen"] 53 | 54 | [dev-dependencies] 55 | divan = { git = "https://github.com/OliverKillane/divan", branch = "enh/file-output" } # json output 56 | nonempty = "0.10.0" 57 | 58 | [[bench]] 59 | name = "against-nonempty" 60 | harness = false 61 | 62 | [package.metadata.docs.rs] 63 | all-features = true 64 | rustdoc-args = ["--cfg", "do_doc_cfg"] 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | The definitive non-empty slice/array/vec library for Rust. 4 | 5 | # Features 6 | Nonempty-by-construction API 7 | ```rust 8 | let mut my_vec = NonEmpty::>::of("hello"); // construct once 9 | my_vec.push("world"); // continue using your normal APIs 10 | let hello: &str = my_vec.first(); // preserve the guarantee that there is at least one element 11 | ``` 12 | 13 | `#[repr(transparent)]` allows advanced usecases and guarantees optimum performance[^1]: 14 | ```rust 15 | let src = &mut ["hello", "world"]; 16 | let ne = NonEmpty::<[_]>::new_mut(src).unwrap(); 17 | // ^ uses the same backing memory 18 | let world: &str = ne.last(); 19 | ``` 20 | 21 | Total API coverage. 22 | For every impl of [`From`], [`TryFrom`], [`PartialEq`] and [`PartialOrd`] in [`std`][^2], 23 | there is a corresponding impl in this library for [`Slice`], [`Array`] and [`Vec`]. 24 | _This includes more exotic types_: 25 | ```rust 26 | let nun: Box> = vec![0xDEAD, 0xBEEF].into(); 27 | let cow: Cow> = (&*nun).into(); 28 | let arc: Arc> = cow.into_owned().into(); 29 | ``` 30 | 31 | `const`-friendly API. Where possible, all methods are `const`. 32 | ```rust 33 | const TWO: &NonEmpty<[&str]> = slice!["together", "forever"]; 34 | const FIRST: &str = TWO.first(); 35 | const ONE: &NonEmpty<[&str]> = NonEmpty::<[_]>::of(&"lonely"); 36 | ``` 37 | 38 | Extensive feature gating supporting: 39 | - `no-std` environments with no allocator. 40 | - `alloc`-enabled environments. 41 | - full-`std`-enabled environments. 42 | - interaction with crates like `serde` and `arbitrary`. 43 | 44 | Iterator support: 45 | Specialized [`Iterator`] methods remove branches to handle empty iterators, 46 | _and_ preserve invariants even when chaining combinators. 47 | ```rust 48 | let v = vec![1, 2, 3]; 49 | let _: Option<&u8> = v.iter().last(); 50 | // ^ normally you have to handle the empty case 51 | let _: &u8 = v.iter_ne().last(); 52 | // ^ but we know there is at least one element 53 | let _: u8 = v.iter_ne().copied().last(); 54 | // ^ using this combinator preserves the invariant 55 | ``` 56 | 57 | Thoughtful design: 58 | - [`NonZeroUsize`] is inserted [where](Slice::len) [appropriate](Vec::truncate). 59 | - Everything [`Deref`](core::ops::Deref)/[`DerefMut`](core::ops::DerefMut)s 60 | down to a [`NonEmpty>`], which in turn `deref/mut`s down to a `[T]`. 61 | - Liberal applications of [`cmp`](core::cmp), [`borrow`](core::borrow), [`convert`](core::convert) 62 | traits. 63 | If there's a missing API that you'd like, please raise an issue! 64 | 65 | [^1]: Other crates like [`nonempty`](https://docs.rs/nonempty/latest/nonempty/struct.NonEmpty.html) 66 | require an indirection. 67 | [^2]: Barring impls on `!#[fundamental]` types like [`Arc`](std::sync::Arc). 68 | Fun fact: our tests were generated from [`std`]'s rustdoc! 69 | 70 | 71 | -------------------------------------------------------------------------------- /benches/against-nonempty.rs: -------------------------------------------------------------------------------- 1 | use std::hint::black_box; 2 | 3 | use divan::Bencher; 4 | 5 | const LENS: &[usize] = &[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]; 6 | 7 | #[divan::bench(types = [Ours, Theirs, Ours, Theirs], args = LENS)] 8 | fn clone(bencher: Bencher, len: usize) 9 | where 10 | B::Subject: Clone, 11 | { 12 | let bench_me = black_box(B::setup(len)); 13 | bencher.bench_local(move || B::run_clone(&bench_me)); 14 | } 15 | 16 | #[divan::bench(types = [Ours, Theirs, Ours, Theirs], args = LENS)] 17 | fn into_iter(bencher: Bencher, len: usize) 18 | where 19 | B::Subject: Clone + IntoIterator, 20 | { 21 | let bench_me = black_box(B::setup(len)); 22 | bencher.bench_local(move || B::run_into_iter(&bench_me)); 23 | } 24 | #[divan::bench(types = [Ours, Theirs, Ours, Theirs], args = LENS)] 25 | fn iter(bencher: Bencher, len: usize) 26 | where 27 | for<'a> &'a B::Subject: IntoIterator, 28 | { 29 | let bench_me = black_box(B::setup(len)); 30 | bencher.bench_local(move || B::run_iter(&bench_me)); 31 | } 32 | #[divan::bench(types = [Ours, Theirs, Ours, Theirs], args = LENS)] 33 | fn partial_eq(bencher: Bencher, len: usize) 34 | where 35 | B::Subject: PartialEq, 36 | { 37 | let left = black_box(B::setup(len)); 38 | let right = black_box(B::setup(len)); 39 | bencher.bench_local(move || B::run_partial_eq(&left, &right)); 40 | } 41 | 42 | struct Ours(std::marker::PhantomData T>); 43 | struct Theirs(std::marker::PhantomData T>); 44 | trait BenchMe { 45 | type Subject; 46 | fn setup(len: usize) -> Self::Subject; 47 | fn run_clone(subject: &Self::Subject) 48 | where 49 | Self::Subject: Clone, 50 | { 51 | black_box(subject.clone()); 52 | } 53 | fn run_into_iter(subject: &Self::Subject) 54 | where 55 | Self::Subject: IntoIterator + Clone, 56 | { 57 | for it in black_box(subject.clone()) { 58 | black_box(it); 59 | } 60 | } 61 | fn run_iter(subject: &Self::Subject) 62 | where 63 | for<'a> &'a Self::Subject: IntoIterator, 64 | { 65 | for it in black_box(subject) { 66 | black_box(it); 67 | } 68 | } 69 | fn run_partial_eq(left: &Self::Subject, right: &Self::Subject) 70 | where 71 | Self::Subject: PartialEq, 72 | { 73 | black_box(black_box(left) == black_box(right)); 74 | } 75 | } 76 | 77 | impl BenchMe for Ours 78 | where 79 | T: Default, 80 | { 81 | type Subject = nunny::Vec; 82 | 83 | fn setup(len: usize) -> Self::Subject { 84 | let mut src = Vec::new(); 85 | src.resize_with(len, Default::default); 86 | black_box(match nunny::Vec::new(src) { 87 | Ok(it) => it, 88 | Err(_) => panic!(), 89 | }) 90 | } 91 | } 92 | impl BenchMe for Theirs 93 | where 94 | T: Default, 95 | { 96 | type Subject = nonempty::NonEmpty; 97 | 98 | fn setup(len: usize) -> Self::Subject { 99 | let mut src = Vec::new(); 100 | src.resize_with(len, Default::default); 101 | black_box(nonempty::NonEmpty::from_vec(src).unwrap()) 102 | } 103 | } 104 | 105 | fn main() { 106 | divan::main() 107 | } 108 | -------------------------------------------------------------------------------- /gen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gen" 3 | version = "0.0.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | anyhow = "1.0.82" 9 | clap = { version = "4.5.4", features = ["derive"] } 10 | prettyplease = "0.2.19" 11 | proc-macro2 = { version = "1.0.81", default-features = false } 12 | quote = { version = "1.0.36", default-features = false } 13 | regex = "1.10.4" 14 | scraper = "0.19.0" 15 | syn = { version = "2.0.60", features = ["extra-traits", "visit-mut"] } 16 | syn-miette = "0.3.0" 17 | ureq = "2.9.6" 18 | owo-colors = "4.0.0" 19 | -------------------------------------------------------------------------------- /gen/src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{Parser, ValueEnum}; 2 | use owo_colors::OwoColorize as _; 3 | use proc_macro2::TokenStream; 4 | use quote::{quote, ToTokens}; 5 | use scraper::{Html, Selector}; 6 | use syn::{ 7 | parse::{Parse, ParseStream, Parser as _}, 8 | punctuated::Punctuated, 9 | visit_mut::{self, VisitMut}, 10 | Generics, Ident, Lifetime, Path, Token, Type, TypePath, 11 | }; 12 | 13 | #[derive(Parser)] 14 | struct Args { 15 | #[arg( 16 | long, 17 | default_value = "https://doc.rust-lang.org/1.77.2/std/convert/trait.From.html" 18 | )] 19 | url: String, 20 | #[arg(long, default_value = "section.impl > .code-header")] 21 | selector: String, 22 | #[arg(long, default_value = "from")] 23 | method: String, 24 | #[arg(long, default_value = "test")] 25 | out: Out, 26 | } 27 | 28 | fn main() -> anyhow::Result<()> { 29 | let Args { 30 | url, 31 | selector, 32 | method, 33 | out, 34 | } = Args::parse(); 35 | let method = Ident::parse.parse_str(&method)?; 36 | let html = ureq::get(&url).call()?.into_string()?; 37 | let html = Html::parse_document(&html); 38 | for selected in 39 | html.select(&Selector::parse(&selector).map_err(|it| anyhow::Error::msg(it.to_string()))?) 40 | { 41 | let text = selected.text().collect::>().join(" "); 42 | eprintln!("{}", text.dimmed()); 43 | 44 | match syn::parse_str::(&text).map(|it| select(it, &method, out)) { 45 | Ok(Some(it)) => { 46 | let rendered = prettyplease::unparse(&syn::File { 47 | shebang: None, 48 | attrs: vec![], 49 | items: vec![syn::parse_quote! { 50 | #it 51 | }], 52 | }); 53 | println!("{}", rendered.green()) 54 | } 55 | Ok(None) => eprintln!("{}", "skip".yellow()), 56 | Err(e) => { 57 | let e = syn_miette::Error::new(e, text).render(); 58 | eprintln!("{}", e.red()); 59 | } 60 | } 61 | } 62 | Ok(()) 63 | } 64 | 65 | #[derive(ValueEnum, Clone, Copy)] 66 | enum Out { 67 | Test, 68 | Impl, 69 | } 70 | 71 | /// Change the types: 72 | /// - [T] -> Slice 73 | /// - [T; N] -> Array 74 | /// 75 | /// Select `impls` with any of the following types: 76 | /// - Slice 77 | /// - Array 78 | /// - Vec 79 | /// 80 | /// Select impls which fill the following: 81 | /// - impl _<$src> for $dst 82 | /// 83 | /// 84 | fn select(mut impl_: Impl, method: &Ident, out: Out) -> Option { 85 | struct Visitor { 86 | include: bool, 87 | } 88 | impl VisitMut for Visitor { 89 | fn visit_type_mut(&mut self, outer: &mut syn::Type) { 90 | match outer { 91 | Type::Array(inner) => { 92 | visit_mut::visit_type_array_mut(self, inner); 93 | let len = &inner.len; 94 | let elem = &inner.elem; 95 | *outer = syn::parse_quote! { 96 | Array<#len, #elem> 97 | }; 98 | self.include = true; 99 | } 100 | Type::BareFn(inner) => visit_mut::visit_type_bare_fn_mut(self, inner), 101 | Type::Group(inner) => visit_mut::visit_type_group_mut(self, inner), 102 | Type::ImplTrait(inner) => visit_mut::visit_type_impl_trait_mut(self, inner), 103 | Type::Infer(inner) => visit_mut::visit_type_infer_mut(self, inner), 104 | Type::Macro(inner) => visit_mut::visit_type_macro_mut(self, inner), 105 | Type::Never(inner) => visit_mut::visit_type_never_mut(self, inner), 106 | Type::Paren(inner) => visit_mut::visit_type_paren_mut(self, inner), 107 | Type::Path(inner) => { 108 | visit_mut::visit_type_path_mut(self, inner); 109 | if inner.path.is_ident("Vec") { 110 | self.include = true; 111 | } 112 | } 113 | Type::Ptr(inner) => visit_mut::visit_type_ptr_mut(self, inner), 114 | Type::Reference(inner) => visit_mut::visit_type_reference_mut(self, inner), 115 | Type::Slice(inner) => { 116 | visit_mut::visit_type_slice_mut(self, inner); 117 | let elem = &inner.elem; 118 | *outer = syn::parse_quote! { 119 | Slice<#elem> 120 | }; 121 | self.include = true; 122 | } 123 | Type::TraitObject(inner) => visit_mut::visit_type_trait_object_mut(self, inner), 124 | Type::Tuple(inner) => visit_mut::visit_type_tuple_mut(self, inner), 125 | Type::Verbatim(_) => {} 126 | other => todo!("{:?}", other), 127 | } 128 | } 129 | } 130 | 131 | let mut visitor = Visitor { include: false }; 132 | 133 | let Impl { 134 | impl_token: _, 135 | generics, 136 | trait_, 137 | for_token: _, 138 | ty, 139 | } = &mut impl_; 140 | 141 | visitor.visit_generics_mut(generics); 142 | visitor.visit_path_mut(trait_); 143 | visitor.visit_type_mut(ty); 144 | 145 | if !visitor.include { 146 | return None; 147 | } 148 | 149 | let Impl { 150 | impl_token: _, 151 | generics: 152 | Generics { 153 | lt_token, 154 | params, 155 | gt_token, 156 | where_clause, 157 | }, 158 | trait_, 159 | for_token: _, 160 | ty: dst, 161 | } = &impl_; 162 | 163 | let src = trait_.segments.last().and_then(|it| match &it.arguments { 164 | syn::PathArguments::None => None, 165 | syn::PathArguments::AngleBracketed(it) => { 166 | let args = it.args.iter().collect::>(); 167 | match args.as_slice() { 168 | [syn::GenericArgument::Type(it)] => Some(it), 169 | _ => None, 170 | } 171 | } 172 | syn::PathArguments::Parenthesized(_) => None, 173 | })?; 174 | 175 | let trait_ = trait_ 176 | .segments 177 | .iter() 178 | .map(|it| &it.ident) 179 | .collect::>(); 180 | 181 | let ret = match out { 182 | Out::Test => quote! { 183 | const _: () = { 184 | fn _test 185 | #lt_token 186 | #params 187 | #gt_token 188 | () 189 | #where_clause 190 | { 191 | <#dst as #trait_<#src>>::#method; 192 | } 193 | } 194 | }, 195 | Out::Impl => quote! { 196 | impl #lt_token #params #gt_token 197 | #trait_<#src> 198 | for #dst 199 | #where_clause 200 | { 201 | fn #method(&self, other: &#src) {} 202 | } 203 | }, 204 | }; 205 | 206 | Some(ret) 207 | } 208 | 209 | #[derive(Debug)] 210 | struct Impl { 211 | pub impl_token: Token![impl], 212 | pub generics: Generics, 213 | pub trait_: Path, 214 | pub for_token: Token![for], 215 | pub ty: Type, 216 | } 217 | 218 | impl ToTokens for Impl { 219 | fn to_tokens(&self, tokens: &mut TokenStream) { 220 | let Self { 221 | impl_token, 222 | generics: 223 | Generics { 224 | lt_token, 225 | params, 226 | gt_token, 227 | where_clause, 228 | }, 229 | trait_, 230 | for_token, 231 | ty, 232 | } = self; 233 | impl_token.to_tokens(tokens); 234 | lt_token.to_tokens(tokens); 235 | params.to_tokens(tokens); 236 | gt_token.to_tokens(tokens); 237 | trait_.to_tokens(tokens); 238 | for_token.to_tokens(tokens); 239 | ty.to_tokens(tokens); 240 | where_clause.to_tokens(tokens); 241 | } 242 | } 243 | 244 | impl Parse for Impl { 245 | // Hacked together from `Parse for syn::ItemImpl` 246 | fn parse(input: ParseStream) -> syn::Result { 247 | let impl_token = input.parse()?; 248 | 249 | let has_generics = input.peek(Token![<]) 250 | && (input.peek2(Token![>]) 251 | || input.peek2(Token![#]) 252 | || (input.peek2(Ident) || input.peek2(Lifetime)) 253 | && (input.peek3(Token![:]) 254 | || input.peek3(Token![,]) 255 | || input.peek3(Token![>]) 256 | || input.peek3(Token![=])) 257 | || input.peek2(Token![const])); 258 | let mut generics: Generics = if has_generics { 259 | input.parse()? 260 | } else { 261 | Generics::default() 262 | }; 263 | 264 | let mut first_ty: Type = input.parse()?; 265 | let trait_; 266 | 267 | let for_token: Token![for] = input.parse()?; 268 | let mut first_ty_ref = &first_ty; 269 | while let Type::Group(ty) = first_ty_ref { 270 | first_ty_ref = &ty.elem; 271 | } 272 | if let Type::Path(TypePath { qself: None, .. }) = first_ty_ref { 273 | while let Type::Group(ty) = first_ty { 274 | first_ty = *ty.elem; 275 | } 276 | if let Type::Path(TypePath { qself: None, path }) = first_ty { 277 | trait_ = path; 278 | } else { 279 | unreachable!(); 280 | } 281 | } else { 282 | return Err(syn::Error::new_spanned(first_ty_ref, "expected trait path")); 283 | } 284 | 285 | let ty = input.parse()?; 286 | if !input.is_empty() { 287 | generics.where_clause = Some(input.parse()?); 288 | } 289 | 290 | Ok(Self { 291 | impl_token, 292 | generics, 293 | trait_, 294 | for_token, 295 | ty, 296 | }) 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /src/arbitrary1.rs: -------------------------------------------------------------------------------- 1 | use arbitrary1::Arbitrary; 2 | 3 | use crate::{Slice, Vec}; 4 | 5 | impl<'a> Arbitrary<'a> for &'a Slice { 6 | fn arbitrary(u: &mut arbitrary1::Unstructured<'a>) -> arbitrary1::Result { 7 | let len = u.arbitrary_len::()?.saturating_add(1); 8 | Ok(Slice::new(u.bytes(len)?).expect("`len` was non-zero")) 9 | } 10 | 11 | fn size_hint(depth: usize) -> (usize, Option) { 12 | let _ = depth; 13 | (1, None) 14 | } 15 | } 16 | 17 | impl<'a, T> Arbitrary<'a> for Vec 18 | where 19 | T: Arbitrary<'a>, 20 | { 21 | fn arbitrary(u: &mut arbitrary1::Unstructured<'a>) -> arbitrary1::Result { 22 | let mut it = Vec::of(u.arbitrary::()?); 23 | for item in u.arbitrary_iter()? { 24 | it.push(item?) 25 | } 26 | Ok(it) 27 | } 28 | 29 | fn size_hint(depth: usize) -> (usize, Option) { 30 | let _ = depth; 31 | (1, None) 32 | } 33 | } 34 | 35 | impl<'a, T> Arbitrary<'a> for Box> 36 | where 37 | T: Arbitrary<'a>, 38 | { 39 | fn arbitrary(u: &mut arbitrary1::Unstructured<'a>) -> arbitrary1::Result { 40 | Ok(Vec::arbitrary(u)?.into_boxed_slice()) 41 | } 42 | 43 | fn size_hint(depth: usize) -> (usize, Option) { 44 | let _ = depth; 45 | (1, None) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/array.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | array, 3 | ops::{Deref, DerefMut}, 4 | }; 5 | 6 | use crate::{Array, NonEmpty, Slice}; 7 | 8 | impl Eq for NonEmpty<[T; N]> where T: Eq {} 9 | 10 | /// [`Array`] methods 11 | impl Array { 12 | /////////// 13 | // Creation 14 | /////////// 15 | 16 | crate::map_non_empty! { 17 | const 18 | /// Returns a [`NonEmpty`] array. 19 | new_ref(&[T; N]) -> &Self: Self::new_ref_unchecked; 20 | 21 | /// Returns a [`NonEmpty`] array. 22 | new_mut(&mut [T; N]) -> &mut Self: Self::new_mut_unchecked; 23 | 24 | /// Returns a [`NonEmpty`] array. 25 | new([T; N]) -> Self: Self::new_unchecked; 26 | } 27 | 28 | crate::transmuting! { 29 | const 30 | /// Create a [`NonEmpty`] array. 31 | new_ref_unchecked(&[T; N]) -> &Self; 32 | 33 | /// Create a [`NonEmpty`] array. 34 | new_mut_unchecked(&mut [T; N]) -> &mut Self; 35 | 36 | // const new_unchecked([T; N]) -> Self; // compiler can't tell this is OK 37 | } 38 | 39 | /// Create a [`NonEmpty`] array. 40 | /// 41 | /// # Safety 42 | /// - `src` must not be empty 43 | pub const unsafe fn new_unchecked(src: [T; N]) -> Self { 44 | Self { inner: src } 45 | } 46 | 47 | //////////// 48 | // Utilities 49 | //////////// 50 | 51 | /// Borrows each element and returns a [`NonEmpty`] array of references with the same size as self. 52 | pub fn each_ref(&self) -> Array<&T, N> { 53 | Array { 54 | inner: self.as_array().each_ref(), 55 | } 56 | } 57 | /// Borrows each element mutably and returns a [`NonEmpty`] array of mutable references with the same size as self. 58 | pub fn each_mut(&mut self) -> Array<&mut T, N> { 59 | Array { 60 | inner: self.as_mut_array().each_mut(), 61 | } 62 | } 63 | /// Returns a [`NonEmpty`] array of the same size as self, with function f applied to each element in order. 64 | #[doc(alias = "map")] // [`<[T; N]>::map`](https://doc.rust-lang.org/std/primitive.array.html#method.map) 65 | pub fn each_map(self, f: F) -> Array 66 | where 67 | F: FnMut(T) -> U, 68 | { 69 | Array { 70 | inner: self.into_array().map(f), 71 | } 72 | } 73 | 74 | /////////////////// 75 | // Inner references 76 | /////////////////// 77 | 78 | /// Returns a [`NonEmpty`] slice. 79 | pub const fn as_slice_ne(&self) -> &Slice { 80 | let src = self.inner.as_slice(); 81 | // Safety 82 | // - src is not empty by construction 83 | unsafe { Slice::new_unchecked(src) } 84 | } 85 | /// Returns a [`NonEmpty`] slice. 86 | pub fn as_mut_slice_ne(&mut self) -> &mut Slice { 87 | let src = self.inner.as_mut_slice(); 88 | // Safety 89 | // - src is not empty by construction 90 | unsafe { Slice::new_mut_unchecked(src) } 91 | } 92 | /// Returns a [`primitive array`](primitive@array). 93 | pub const fn as_array(&self) -> &[T; N] { 94 | &self.inner 95 | } 96 | /// Returns a [`primitive array`](primitive@array). 97 | pub fn as_mut_array(&mut self) -> &mut [T; N] { 98 | &mut self.inner 99 | } 100 | /// Returns a [`primitive array`](primitive@array). 101 | pub fn into_array(self) -> [T; N] { 102 | let Self { inner } = self; 103 | inner 104 | } 105 | } 106 | 107 | /// Known non-empty iterator for [`Array`]. 108 | impl Array { 109 | pub fn into_iter_ne(self) -> NonEmpty> { 110 | NonEmpty { 111 | inner: self.into_iter(), 112 | } 113 | } 114 | } 115 | 116 | /// Special case for [`Array`]s of length one 117 | impl Array { 118 | /// Create a [`NonEmpty`] array of a single element 119 | pub const fn of(item: T) -> Self { 120 | let src = [item]; 121 | unsafe { Self::new_unchecked(src) } 122 | } 123 | /// Create a [`NonEmpty`] array of a single mutable reference 124 | pub fn of_mut(item: &mut T) -> &mut Self { 125 | let src = array::from_mut(item); 126 | unsafe { Self::new_mut_unchecked(src) } 127 | } 128 | /// Create a [`NonEmpty`] array of a single reference 129 | pub const fn of_ref(item: &T) -> &Self { 130 | let src = array::from_ref(item); 131 | unsafe { Self::new_ref_unchecked(src) } 132 | } 133 | } 134 | 135 | /// [`Array`] to [`Slice`] 136 | impl Deref for Array { 137 | type Target = Slice; 138 | 139 | fn deref(&self) -> &Self::Target { 140 | self.as_slice_ne() 141 | } 142 | } 143 | /// [`Array`] to [`Slice`] 144 | impl DerefMut for Array { 145 | fn deref_mut(&mut self) -> &mut Self::Target { 146 | self.as_mut_slice_ne() 147 | } 148 | } 149 | 150 | crate::as_ref_as_mut! { 151 | for Array as [T]; 152 | for Array as Slice; 153 | for Array as Self; 154 | } 155 | 156 | crate::borrow_borrow_mut! { 157 | for Array as [T]; 158 | for Array as Slice; 159 | } 160 | 161 | crate::slice_iter! { 162 | for Array 163 | } 164 | 165 | impl IntoIterator for Array { 166 | type Item = T; 167 | 168 | type IntoIter = core::array::IntoIter; 169 | 170 | fn into_iter(self) -> Self::IntoIter { 171 | self.into_array().into_iter() 172 | } 173 | } 174 | 175 | mod partial_eq_std { 176 | use super::*; 177 | 178 | impl PartialEq<[U]> for Array 179 | where 180 | T: PartialEq, 181 | { 182 | fn eq(&self, other: &[U]) -> bool { 183 | <[_] as PartialEq<[_]>>::eq(self, other) 184 | } 185 | } 186 | impl PartialEq<[U; N]> for Array 187 | where 188 | T: PartialEq, 189 | { 190 | fn eq(&self, other: &[U; N]) -> bool { 191 | <[_] as PartialEq<[_]>>::eq(self, other) 192 | } 193 | } 194 | #[cfg(feature = "alloc")] 195 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 196 | impl PartialEq> for Array 197 | where 198 | T: PartialEq, 199 | { 200 | fn eq(&self, other: &alloc::vec::Vec) -> bool { 201 | <[_] as PartialEq<[_]>>::eq(self, other) 202 | } 203 | } 204 | 205 | // converse 206 | //--------- 207 | 208 | impl PartialEq> for [U] 209 | where 210 | U: PartialEq, 211 | { 212 | fn eq(&self, other: &Array) -> bool { 213 | <[_] as PartialEq<[_]>>::eq(self, other) 214 | } 215 | } 216 | impl PartialEq> for [U; N] 217 | where 218 | U: PartialEq, 219 | { 220 | fn eq(&self, other: &Array) -> bool { 221 | <[_] as PartialEq<[_]>>::eq(self, other) 222 | } 223 | } 224 | #[cfg(feature = "alloc")] 225 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 226 | impl PartialEq> for alloc::vec::Vec 227 | where 228 | U: PartialEq, 229 | { 230 | fn eq(&self, other: &Array) -> bool { 231 | <[_] as PartialEq<[_]>>::eq(self, other) 232 | } 233 | } 234 | } 235 | mod cmp_std { 236 | use core::cmp::Ordering; 237 | 238 | use super::*; 239 | 240 | impl PartialOrd<[T]> for Array 241 | where 242 | T: PartialOrd, 243 | { 244 | fn partial_cmp(&self, other: &[T]) -> Option { 245 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 246 | } 247 | } 248 | impl PartialOrd<[T; N]> for Array 249 | where 250 | T: PartialOrd, 251 | { 252 | fn partial_cmp(&self, other: &[T; N]) -> Option { 253 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 254 | } 255 | } 256 | #[cfg(feature = "alloc")] 257 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 258 | impl PartialOrd> for Array 259 | where 260 | T: PartialOrd, 261 | { 262 | fn partial_cmp(&self, other: &alloc::vec::Vec) -> Option { 263 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 264 | } 265 | } 266 | 267 | // converse 268 | //--------- 269 | 270 | impl PartialOrd> for [T] 271 | where 272 | T: PartialOrd, 273 | { 274 | fn partial_cmp(&self, other: &Array) -> Option { 275 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 276 | } 277 | } 278 | impl PartialOrd> for [T; N] 279 | where 280 | T: PartialOrd, 281 | { 282 | fn partial_cmp(&self, other: &Array) -> Option { 283 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 284 | } 285 | } 286 | #[cfg(feature = "alloc")] 287 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 288 | impl PartialOrd> for alloc::vec::Vec 289 | where 290 | T: PartialOrd, 291 | { 292 | fn partial_cmp(&self, other: &Array) -> Option { 293 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 294 | } 295 | } 296 | } 297 | 298 | mod convert_std { 299 | use crate::Error; 300 | 301 | use super::*; 302 | 303 | impl TryFrom<[T; N]> for Array { 304 | type Error = Error; 305 | 306 | fn try_from(value: [T; N]) -> Result { 307 | Self::new(value).ok_or(Error(())) 308 | } 309 | } 310 | impl<'a, T, const N: usize> TryFrom<&'a [T; N]> for &'a Array { 311 | type Error = Error; 312 | 313 | fn try_from(value: &'a [T; N]) -> Result { 314 | Array::new_ref(value).ok_or(Error(())) 315 | } 316 | } 317 | impl<'a, T, const N: usize> TryFrom<&'a mut [T; N]> for &'a mut Array { 318 | type Error = Error; 319 | 320 | fn try_from(value: &'a mut [T; N]) -> Result { 321 | Array::new_mut(value).ok_or(Error(())) 322 | } 323 | } 324 | 325 | impl From> for [T; N] { 326 | fn from(value: Array) -> Self { 327 | value.into_array() 328 | } 329 | } 330 | impl<'a, T, const N: usize> From<&'a Array> for &'a [T; N] { 331 | fn from(value: &'a Array) -> Self { 332 | value.as_array() 333 | } 334 | } 335 | impl<'a, T, const N: usize> From<&'a mut Array> for &'a mut [T; N] { 336 | fn from(value: &'a mut Array) -> Self { 337 | value.as_mut_array() 338 | } 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /src/iter.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | cmp::Ordering, 3 | iter::{ 4 | Chain, Cloned, Copied, Cycle, Enumerate, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Take, 5 | }, 6 | num::NonZeroUsize, 7 | }; 8 | 9 | use crate::NonEmpty; 10 | 11 | macro_rules! unwrap { 12 | ($expr:expr) => { 13 | match $expr { 14 | Some(it) => it, 15 | // Safety: 16 | // - NonEmpty is only constructed from known NonEmpty items 17 | // - NonEmpty does give out mutable access to the inner iterator 18 | // (so it always has one element) 19 | None => unsafe { crate::unreachable() }, 20 | } 21 | }; 22 | } 23 | 24 | /// Methods on [`Iterator`]s with a non-empty invariant. 25 | /// 26 | /// See [`Self::relax`] to access the normal iterator inside. 27 | impl NonEmpty 28 | where 29 | I: Iterator, 30 | { 31 | /// [`NonEmpty`] version of [`Iterator::next`]. 32 | /// ``` 33 | /// # use nunny::{vec}; 34 | /// let v = vec![1, 2, 3]; 35 | /// let _: Option<&u8> = v.iter().next(); 36 | /// // ^ normally you have to handle the empty case 37 | /// let _: &u8 = v.iter_ne().first(); 38 | /// // ^ but we know there is at least one element 39 | /// ``` 40 | pub fn first(mut self) -> I::Item { 41 | unwrap!(self.inner.next()) 42 | } 43 | /// [`NonEmpty`] version of [`Iterator::last`]. 44 | /// ``` 45 | /// # use nunny::{vec}; 46 | /// let v = vec![1, 2, 3]; 47 | /// let _: Option<&u8> = v.iter().last(); 48 | /// // ^ normally you have to handle the empty case 49 | /// let _: &u8 = v.iter_ne().last(); 50 | /// // ^ but we know there is at least one element 51 | /// ``` 52 | pub fn last(self) -> I::Item { 53 | unwrap!(self.inner.last()) 54 | } 55 | /// [`NonEmpty`] version of [`Iterator::map`]. 56 | /// ``` 57 | /// # use nunny::{slice}; 58 | /// let iter = slice![1, 2, 3].iter_ne(); 59 | /// assert_eq!( 60 | /// iter.map(|it| *it * 2).last(), 61 | /// // ^ the invariant is maintained 62 | /// // so we _know_ there's a last element 63 | /// 6 64 | /// ); 65 | /// ``` 66 | pub fn map(self, f: F) -> NonEmpty> 67 | where 68 | F: FnMut(I::Item) -> B, 69 | { 70 | NonEmpty { 71 | inner: self.inner.map(f), 72 | } 73 | } 74 | /// [`NonEmpty`] version of [`Iterator::chain`]. 75 | /// ``` 76 | /// # use nunny::{slice}; 77 | /// let iter = slice![1, 2].iter_ne(); 78 | /// assert_eq!( 79 | /// iter.chain(&[3]).last(), 80 | /// // ^ the invariant is maintained 81 | /// // so we _know_ there's a last element 82 | /// &3 83 | /// ); 84 | /// ``` 85 | pub fn chain(self, other: U) -> NonEmpty::IntoIter>> 86 | where 87 | U: IntoIterator, 88 | { 89 | NonEmpty { 90 | inner: self.inner.chain(other), 91 | } 92 | } 93 | /// [`NonEmpty`] version of [`Iterator::enumerate`]. 94 | /// ``` 95 | /// # use nunny::{slice}; 96 | /// let iter = slice!['a', 'b'].iter_ne(); 97 | /// assert_eq!( 98 | /// iter.enumerate().last(), 99 | /// // ^ the invariant is maintained 100 | /// // so we _know_ there's a last element 101 | /// (1, &'b') 102 | /// ); 103 | /// ``` 104 | pub fn enumerate(self) -> NonEmpty> { 105 | NonEmpty { 106 | inner: self.inner.enumerate(), 107 | } 108 | } 109 | /// [`NonEmpty`] version of [`Iterator::peekable`], allowing you to use 110 | /// [`Self::peek`] and [`Self::peek_mut`] 111 | /// ``` 112 | /// # use nunny::{vec, NonEmpty}; 113 | /// let mut peek_me = vec!['a', 'b'].into_iter_ne().peekable(); 114 | /// assert_eq!( 115 | /// *peek_me.peek(), 116 | /// 'a' 117 | /// ); 118 | /// *peek_me.peek_mut() = 'b'; 119 | /// assert_eq!( 120 | /// peek_me.collect_vec(), 121 | /// ['b', 'b'] 122 | /// ); 123 | /// ``` 124 | pub fn peekable(self) -> NonEmpty> { 125 | NonEmpty { 126 | inner: self.inner.peekable(), 127 | } 128 | } 129 | /// [`NonEmpty`] version of [`Iterator::take`]. 130 | /// 131 | /// Note that `n` cannot be zero, to maintain the [`NonEmpty`] invariant. 132 | /// 133 | /// ``` 134 | /// # use nunny::{slice, nonzero}; 135 | /// let iter = slice!['a', 'b'].iter_ne(); 136 | /// assert_eq!( 137 | /// iter.take(nonzero!(1)).last(), 138 | /// // ^ compile time checked 139 | /// &'a' 140 | /// ) 141 | /// ``` 142 | pub fn take(self, n: NonZeroUsize) -> NonEmpty> { 143 | NonEmpty { 144 | inner: self.inner.take(n.get()), 145 | } 146 | } 147 | // pub fn flat_map 148 | /// [`NonEmpty`] version of [`Iterator::flatten`]. 149 | /// 150 | /// Note that the inner items must also be [`NonEmpty`], to maintain the invariant. 151 | /// ``` 152 | /// use nunny::{vec}; 153 | /// let nested = vec![vec![1], vec![2, 3]]; 154 | /// assert_eq!( 155 | /// nested.into_iter_ne().flatten().collect_vec(), 156 | /// [1, 2, 3], 157 | /// ); 158 | /// ``` 159 | #[allow(clippy::type_complexity)] 160 | pub fn flatten(self) -> NonEmpty II>> 161 | where 162 | I: Iterator>, 163 | // ^ each item is nonempty 164 | II: IntoIterator, 165 | // TODO(aatifsyed): a trait NonEmptyIterator would make this more ergonomic 166 | // See commit history for an attempt 167 | { 168 | NonEmpty { 169 | inner: self.inner.flat_map(|it| it.inner), 170 | } 171 | } 172 | /// [`NonEmpty`] version of [`Iterator::fuse`]. 173 | pub fn fuse(self) -> NonEmpty> { 174 | NonEmpty { 175 | inner: self.inner.fuse(), 176 | } 177 | } 178 | /// [`NonEmpty`] version of [`Iterator::inspect`]. 179 | pub fn inspect(self, f: F) -> NonEmpty> 180 | where 181 | F: FnMut(&I::Item), 182 | { 183 | NonEmpty { 184 | inner: self.inner.inspect(f), 185 | } 186 | } 187 | /// [`NonEmpty`] version of [`Iterator::reduce`]. 188 | /// ``` 189 | /// # use nunny::{vec}; 190 | /// # use core::cmp::min; 191 | /// let v = vec![1, 2, 3]; 192 | /// let _: Option<&u8> = v.iter().reduce(min); 193 | /// // ^ normally you have to handle the empty case 194 | /// let _: &u8 = v.iter_ne().reduce(min); 195 | /// // ^ but we know there is at least one element 196 | /// ``` 197 | pub fn reduce(self, f: F) -> I::Item 198 | where 199 | F: FnMut(I::Item, I::Item) -> I::Item, 200 | { 201 | unwrap!(self.inner.reduce(f)) 202 | } 203 | /// [`NonEmpty`] version of [`Iterator::max`]. 204 | /// ``` 205 | /// # use nunny::{vec}; 206 | /// let v = vec![1, 2, 3]; 207 | /// let _: Option<&u8> = v.iter().max(); 208 | /// // ^ normally you have to handle the empty case 209 | /// let _: &u8 = v.iter_ne().max(); 210 | /// // ^ but we know there is at least one element 211 | /// ``` 212 | pub fn max(self) -> I::Item 213 | where 214 | I::Item: Ord, 215 | { 216 | unwrap!(self.inner.max()) 217 | } 218 | /// [`NonEmpty`] version of [`Iterator::min`]. 219 | /// ``` 220 | /// # use nunny::{vec}; 221 | /// let v = vec![1, 2, 3]; 222 | /// let _: Option<&u8> = v.iter().min(); 223 | /// // ^ normally you have to handle the empty case 224 | /// let _: &u8 = v.iter_ne().min(); 225 | /// // ^ but we know there is at least one element 226 | /// ``` 227 | pub fn min(self) -> I::Item 228 | where 229 | I::Item: Ord, 230 | { 231 | unwrap!(self.inner.min()) 232 | } 233 | /// [`NonEmpty`] version of [`Iterator::max_by_key`]. 234 | pub fn max_by_key(self, f: F) -> I::Item 235 | where 236 | B: Ord, 237 | F: FnMut(&I::Item) -> B, 238 | { 239 | unwrap!(self.inner.max_by_key(f)) 240 | } 241 | /// [`NonEmpty`] version of [`Iterator::max_by`]. 242 | pub fn max_by(self, compare: F) -> I::Item 243 | where 244 | F: FnMut(&I::Item, &I::Item) -> Ordering, 245 | { 246 | unwrap!(self.inner.max_by(compare)) 247 | } 248 | /// [`NonEmpty`] version of [`Iterator::min_by_key`]. 249 | pub fn min_by_key(self, f: F) -> I::Item 250 | where 251 | B: Ord, 252 | F: FnMut(&I::Item) -> B, 253 | { 254 | unwrap!(self.inner.min_by_key(f)) 255 | } 256 | /// [`NonEmpty`] version of [`Iterator::min_by`]. 257 | pub fn min_by(self, compare: F) -> I::Item 258 | where 259 | F: FnMut(&I::Item, &I::Item) -> Ordering, 260 | { 261 | unwrap!(self.inner.min_by(compare)) 262 | } 263 | /// [`NonEmpty`] version of [`Iterator::rev`]. 264 | pub fn rev(self) -> NonEmpty> 265 | where 266 | I: DoubleEndedIterator, 267 | { 268 | NonEmpty { 269 | inner: self.inner.rev(), 270 | } 271 | } 272 | 273 | /// [`NonEmpty`] version of [`Iterator::unzip`]. 274 | #[cfg(feature = "alloc")] 275 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 276 | pub fn unzip_vec(self) -> (crate::Vec, crate::Vec) 277 | where 278 | I: Iterator, 279 | { 280 | let (a, b) = self.inner.unzip(); 281 | // Safety: 282 | // - NonEmpty is only constructed from known NonEmpty items 283 | // - NonEmpty does not allow mutable access to the inner iterator 284 | // (so it always has one element) 285 | unsafe { (crate::Vec::new_unchecked(a), crate::Vec::new_unchecked(b)) } 286 | } 287 | /// [`NonEmpty`] version of [`Iterator::copied`]. 288 | pub fn copied<'a, T>(self) -> NonEmpty> 289 | where 290 | T: 'a + Copy, 291 | I: Iterator, 292 | { 293 | NonEmpty { 294 | inner: self.inner.copied(), 295 | } 296 | } 297 | /// [`NonEmpty`] version of [`Iterator::cloned`]. 298 | pub fn cloned<'a, T>(self) -> NonEmpty> 299 | where 300 | T: 'a + Clone, 301 | I: Iterator, 302 | { 303 | NonEmpty { 304 | inner: self.inner.cloned(), 305 | } 306 | } 307 | /// [`NonEmpty`] version of [`Iterator::cycle`]. 308 | pub fn cycle(self) -> NonEmpty> 309 | where 310 | I: Clone, 311 | { 312 | NonEmpty { 313 | inner: self.inner.cycle(), 314 | } 315 | } 316 | /// Remove the [`NonEmpty`] wrapper, allowing you to access normal iterator 317 | /// methods like [`Iterator::filter`]. 318 | #[doc(alias = "into_iter")] 319 | #[doc(alias = "into_inner")] 320 | pub fn relax(self) -> I { 321 | self.inner 322 | } 323 | /// Collect this iterator into a [`NonEmpty`]. 324 | #[cfg(feature = "alloc")] 325 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 326 | pub fn collect_vec(self) -> crate::Vec { 327 | // Safety: 328 | // - NonEmpty is only constructed from known NonEmpty items 329 | // - NonEmpty does not allow mutable access to the inner iterator 330 | // (so it always has one element) 331 | unsafe { crate::Vec::new_unchecked(self.inner.collect()) } 332 | } 333 | /// Collect [`Ok`] items into a [`NonEmpty`], short-circuiting on [`Err`]. 334 | #[cfg(feature = "alloc")] 335 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 336 | pub fn try_collect_vec(self) -> Result, E> 337 | where 338 | I: Iterator>, 339 | { 340 | match self.inner.collect() { 341 | // Safety: 342 | // - NonEmpty is only constructed from known NonEmpty items 343 | // - NonEmpty does not allow mutable access to the inner iterator 344 | // (so it always has one element) 345 | Ok(it) => Ok(unsafe { crate::Vec::new_unchecked(it) }), 346 | Err(e) => Err(e), 347 | } 348 | } 349 | } 350 | 351 | impl NonEmpty> 352 | where 353 | I: Iterator, 354 | { 355 | /// Peek this [`NonEmpty`] iterator, without advancing it. 356 | /// 357 | /// See [`Self::peekable`]. 358 | pub fn peek(&mut self) -> &I::Item { 359 | unwrap!(self.inner.peek()) 360 | } 361 | /// Peek and modify this [`NonEmpty`] iterator, without advancing it. 362 | /// 363 | /// See [`Self::peekable`]. 364 | pub fn peek_mut(&mut self) -> &mut I::Item { 365 | unwrap!(self.inner.peek_mut()) 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The definitive non-empty slice/array/vec library for Rust. 2 | //! 3 | //! # Features 4 | //! Nonempty-by-construction API 5 | //! ``` 6 | //! # use nunny::NonEmpty; 7 | //! let mut my_vec = NonEmpty::>::of("hello"); // construct once 8 | //! my_vec.push("world"); // continue using your normal APIs 9 | //! let hello: &str = my_vec.first(); // preserve the guarantee that there is at least one element 10 | //! ``` 11 | //! 12 | //! `#[repr(transparent)]` allows advanced usecases and guarantees optimum performance[^1]: 13 | //! ``` 14 | //! # use nunny::NonEmpty; 15 | //! let src = &mut ["hello", "world"]; 16 | //! let ne = NonEmpty::<[_]>::new_mut(src).unwrap(); 17 | //! // ^ uses the same backing memory 18 | //! let world: &str = ne.last(); 19 | //! ``` 20 | //! 21 | //! Total API coverage. 22 | //! For every impl of [`From`], [`TryFrom`], [`PartialEq`] and [`PartialOrd`] in [`std`][^2], 23 | //! there is a corresponding impl in this library for [`Slice`], [`Array`] and [`Vec`]. 24 | //! _This includes more exotic types_: 25 | //! ``` 26 | //! # use nunny::{vec, NonEmpty}; 27 | //! # use std::{borrow::Cow, sync::Arc}; 28 | //! let nun: Box> = vec![0xDEAD, 0xBEEF].into(); 29 | //! let cow: Cow> = (&*nun).into(); 30 | //! let arc: Arc> = cow.into_owned().into(); 31 | //! ``` 32 | //! 33 | //! `const`-friendly API. Where possible, all methods are `const`. 34 | //! ``` 35 | //! # use nunny::{NonEmpty, slice}; 36 | //! const TWO: &NonEmpty<[&str]> = slice!["together", "forever"]; 37 | //! const FIRST: &str = TWO.first(); 38 | //! const ONE: &NonEmpty<[&str]> = NonEmpty::<[_]>::of(&"lonely"); 39 | //! ``` 40 | //! 41 | //! Extensive feature gating supporting: 42 | //! - `no-std` environments with no allocator. 43 | //! - `alloc`-enabled environments. 44 | //! - full-`std`-enabled environments. 45 | //! - interaction with crates like [`serde`](::serde1) and [`arbitrary`](::arbitrary1). 46 | //! 47 | //! Iterator support: 48 | //! Specialized [`Iterator`] methods remove branches to handle empty iterators, 49 | //! _and_ preserve invariants even when chaining combinators. 50 | //! ``` 51 | //! # use nunny::{vec}; 52 | //! let v = vec![1, 2, 3]; 53 | //! let _: Option<&u8> = v.iter().last(); 54 | //! // ^ normally you have to handle the empty case 55 | //! let _: &u8 = v.iter_ne().last(); 56 | //! // ^ but we know there is at least one element 57 | //! let _: u8 = v.iter_ne().copied().last(); 58 | //! // ^ using this combinator preserves the invariant 59 | //! ``` 60 | //! 61 | //! Thoughtful design: 62 | //! - [`NonZeroUsize`] is inserted [where](Slice::len_ne) [appropriate](Vec::truncate). 63 | //! - Everything [`Deref`](core::ops::Deref)/[`DerefMut`](core::ops::DerefMut)s 64 | //! down to a [`NonEmpty>`], which in turn `deref/mut`s down to a `[T]`. 65 | //! - Liberal applications of [`cmp`](core::cmp), [`borrow`](core::borrow), [`convert`](core::convert) 66 | //! traits. 67 | //! If there's a missing API that you'd like, please raise an issue! 68 | //! 69 | //! [^1]: Other crates like [`nonempty`](https://docs.rs/nonempty/latest/nonempty/struct.NonEmpty.html) 70 | //! require an indirection. 71 | //! [^2]: Barring impls on `!#[fundamental]` types like [`Arc`](std::sync::Arc). 72 | //! Fun fact: our tests were generated from [`std`]'s rustdoc! 73 | 74 | #![cfg_attr(not(feature = "std"), no_std)] 75 | #![cfg_attr(do_doc_cfg, feature(doc_cfg))] 76 | 77 | #[cfg(feature = "alloc")] 78 | extern crate alloc; 79 | #[cfg(feature = "arbitrary1")] 80 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "arbitrary")))] 81 | mod arbitrary1; 82 | #[cfg(feature = "proptest1")] 83 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "proptest")))] 84 | mod proptest1; 85 | #[cfg(feature = "quickcheck1")] 86 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "quickcheck")))] 87 | mod quickcheck1; 88 | #[cfg(feature = "schemars08")] 89 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "schemars")))] 90 | mod schemars08; 91 | #[cfg(feature = "serde1")] 92 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "serde")))] 93 | mod serde1; 94 | 95 | mod array; 96 | mod iter; 97 | mod mirror_std { 98 | mod cmp; 99 | mod from; 100 | mod partial_eq; 101 | mod try_from; 102 | } 103 | mod slice; 104 | #[cfg(feature = "alloc")] 105 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 106 | mod vec; 107 | 108 | use core::{convert::Infallible, fmt, num::NonZeroUsize}; 109 | 110 | /// A wrapper struct around non-empty slices/arrays/vectors. 111 | /// 112 | /// You may wish to use the following type aliases instead: 113 | /// - [`Slice`]. 114 | /// - [`Vec`]. 115 | /// - [`Array`]. 116 | /// 117 | /// See also [crate documentation](crate) 118 | #[derive(Debug, Clone, Copy, Hash)] 119 | #[repr(transparent)] 120 | pub struct NonEmpty { 121 | inner: T, 122 | } 123 | 124 | /// A non-empty [prim@array] of known size. 125 | pub type Array = NonEmpty<[T; N]>; 126 | /// A non-empty, dynamically sized [prim@slice]. 127 | pub type Slice = NonEmpty<[T]>; 128 | /// A non-empty, heap allocated [Vec](alloc::vec::Vec). 129 | #[cfg(feature = "alloc")] 130 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 131 | pub type Vec = NonEmpty>; 132 | 133 | /// Create a non-empty slice 134 | /// ``` 135 | /// # use nunny::{NonEmpty, slice}; 136 | /// const SLICE: &NonEmpty<[&str]> = slice!["hello", "world"]; 137 | /// ``` 138 | /// 139 | /// Note that no `slice_mut` is provided[^1] - users are expected to use [`array!`] 140 | /// and [`Array::as_mut_slice`] as required. 141 | /// 142 | /// [^1]: See [this blog post](https://blog.m-ou.se/super-let/) for more on why 143 | /// `slice_mut` is impossible to implement in Rust today. 144 | #[macro_export] 145 | macro_rules! slice { 146 | ($($el:expr),+ $(,)?) => { 147 | // Safety: 148 | // - `+` guarantees that at least one item is given 149 | unsafe { 150 | $crate::Slice::new_unchecked(&[$($el),*]) 151 | } 152 | }; 153 | } 154 | 155 | /// Create a non-empty array 156 | /// ``` 157 | /// # use nunny::array; 158 | /// let mut arr = array!["hello", "world"]; 159 | /// *arr.first_mut() = "goodbye"; 160 | /// assert_eq!(arr, ["goodbye", "world"]) 161 | /// ``` 162 | #[macro_export] 163 | macro_rules! array { 164 | ($($el:expr),+ $(,)?) => { 165 | // Safety: 166 | // - `+` guarantees that at least one item is given 167 | unsafe { 168 | $crate::Array::new_unchecked([$($el),*]) 169 | } 170 | }; 171 | } 172 | 173 | /// Create a non-empty heap-allocated vector 174 | /// ``` 175 | /// # use nunny::{NonEmpty, vec}; 176 | /// let mut v = vec!["hello", "world"]; 177 | /// *v.first_mut() = "goodbye"; 178 | /// assert_eq!(v, ["goodbye", "world"]) 179 | /// ``` 180 | /// 181 | /// For `vec![T; N]`, `N` must be evaluatable at `const` time, and `T` must be [`Clone`]. 182 | /// ```compile_fail 183 | /// # use nunny::vec; 184 | /// let len = 1 + 1; // runtime variable 185 | /// let v = vec!["hello"; len]; 186 | /// ``` 187 | /// ``` 188 | /// # use nunny::vec; 189 | /// let v = vec!["hello"; 1 + 1]; // compile time nonzero 190 | /// ``` 191 | /// ```compile_fail 192 | /// # use nunny::vec; 193 | /// let v = vec!["hello"; 0]; // not allowed to be zero! 194 | /// ``` 195 | #[cfg(feature = "alloc")] 196 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 197 | #[macro_export] 198 | macro_rules! vec { 199 | ($($el:expr),+ $(,)?) => { 200 | // Safety: 201 | // - `+` guarantees that at least one item is given 202 | $crate::Vec::from(unsafe { 203 | $crate::Array::new_unchecked([$($el),*]) 204 | }) 205 | }; 206 | ($el:expr; $n:expr) => { 207 | $crate::Vec::filled($el, $crate::nonzero!($n)) 208 | } 209 | } 210 | 211 | /// Checks that an expression is non-zero _at compile time_. 212 | /// 213 | /// Provided as a convenience for writing tests. 214 | /// 215 | /// ``` 216 | /// # use core::num::NonZeroUsize; 217 | /// # use nunny::nonzero; 218 | /// const NONZERO: NonZeroUsize = nonzero!(1); 219 | /// ``` 220 | /// ```compile_fail 221 | /// # use core::num::NonZeroUsize; 222 | /// # use nunny::nonzero; 223 | /// const OOPS: NonZeroUsize = nonzero!(0); 224 | /// ``` 225 | #[doc(hidden)] 226 | #[macro_export] 227 | macro_rules! nonzero { 228 | ($expr:expr) => {{ 229 | const NONZERO: $crate::__private::core::num::NonZeroUsize = 230 | match $crate::__private::core::num::NonZeroUsize::new($expr) { 231 | $crate::__private::core::option::Option::Some(it) => it, 232 | _ => $crate::__private::core::panic!("expression evaluated to zero"), 233 | }; 234 | NONZERO 235 | }}; 236 | } 237 | 238 | /// Implementation detail, semver-exempt. 239 | #[doc(hidden)] 240 | pub mod __private { 241 | pub extern crate core; 242 | } 243 | 244 | /// Error returned in [`TryFrom`] implementations for reference conversions. 245 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 246 | pub struct Error(()); 247 | 248 | impl fmt::Display for Error { 249 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 250 | f.write_str("collection was empty") 251 | } 252 | } 253 | 254 | #[cfg(feature = "std")] 255 | impl std::error::Error for Error {} 256 | 257 | macro_rules! transmuting { 258 | () => {}; // base case 259 | (const $(#[$meta:meta])* $ident:ident($in:ty) -> $out:ty; $($rest:tt)*) => { 260 | $(#[$meta])* 261 | /// 262 | /// # Safety 263 | /// - `src` must not be empty 264 | pub const unsafe fn $ident(src: $in) -> $out { 265 | debug_assert!(!src.is_empty()); 266 | // Safety 267 | // - #[repr(transparent)] 268 | unsafe { core::mem::transmute(src) } 269 | } 270 | $crate::transmuting!($($rest)*); 271 | }; 272 | ($(#[$meta:meta])* $ident:ident($in:ty) -> $out:ty; $($rest:tt)*) => { 273 | $(#[$meta])* 274 | /// 275 | /// # Safety 276 | /// - `src` must not be empty 277 | pub unsafe fn $ident(src: $in) -> $out { 278 | debug_assert!(!src.is_empty()); 279 | // Safety 280 | // - #[repr(transparent)] 281 | unsafe { core::mem::transmute(src) } 282 | } 283 | $crate::transmuting!($($rest)*); 284 | }; 285 | } 286 | pub(crate) use transmuting; 287 | 288 | macro_rules! map_non_empty { 289 | () => {}; // base case 290 | (const $(#[$meta:meta])* $ident:ident($in:ty) -> $out:ty: $mapper:path; $($rest:tt)*) => { 291 | $(#[$meta])* 292 | /// 293 | /// Returns [`None`] if `src` is empty. 294 | pub const fn $ident(src: $in) -> Option<$out> { 295 | match src.is_empty() { 296 | true => None, 297 | // Safety 298 | // - checked non empty 299 | false => Some(unsafe { $mapper(src) }) 300 | } 301 | } 302 | $crate::map_non_empty!($($rest)*); 303 | }; 304 | ($(#[$meta:meta])* $ident:ident($in:ty) -> $out:ty: $mapper:path; $($rest:tt)*) => { 305 | $(#[$meta])* 306 | /// 307 | /// Returns [`None`] if `src` is empty. 308 | pub fn $ident(src: $in) -> Option<$out> { 309 | match src.is_empty() { 310 | true => None, 311 | // Safety 312 | // - checked non empty 313 | false => Some(unsafe { $mapper(src) }) 314 | } 315 | } 316 | $crate::map_non_empty!($($rest)*); 317 | }; 318 | } 319 | pub(crate) use map_non_empty; 320 | 321 | macro_rules! as_ref_as_mut { 322 | ($($(<$ty_param:ident $(, const $const_param:ident: usize)?>)? for $self:ty as $ty:ty);* $(;)?) => { 323 | $( 324 | impl$(<$ty_param $(, const $const_param: usize)?>)? ::core::convert::AsRef<$ty> for $self { 325 | fn as_ref(&self) -> &$ty { self } 326 | } 327 | 328 | impl$(<$ty_param $(, const $const_param: usize)?>)? ::core::convert::AsMut<$ty> for $self { 329 | fn as_mut(&mut self) -> &mut $ty { self } 330 | } 331 | 332 | )* 333 | }; 334 | } 335 | pub(crate) use as_ref_as_mut; 336 | 337 | macro_rules! borrow_borrow_mut { 338 | ($($(<$ty_param:ident $(, const $const_param:ident: usize)?>)? for $self:ty as $ty:ty);* $(;)?) => { 339 | $( 340 | impl$(<$ty_param $(, const $const_param: usize)?>)? ::core::borrow::Borrow<$ty> for $self { 341 | fn borrow(&self) -> &$ty { self } 342 | } 343 | 344 | impl$(<$ty_param $(, const $const_param: usize)?>)? ::core::borrow::BorrowMut<$ty> for $self { 345 | fn borrow_mut(&mut self) -> &mut $ty { self } 346 | } 347 | 348 | )* 349 | }; 350 | } 351 | pub(crate) use borrow_borrow_mut; 352 | 353 | macro_rules! slice_iter { 354 | (<$ty_param:ident $(, const $const_param:ident: usize)?> for $self:ty) => { 355 | impl<'a, $ty_param $(, const $const_param: usize)?> ::core::iter::IntoIterator for &'a $self { 356 | type Item = &'a $ty_param; 357 | type IntoIter = ::core::slice::Iter<'a, T>; 358 | fn into_iter(self) -> Self::IntoIter { 359 | self.iter() 360 | } 361 | } 362 | 363 | impl<'a, $ty_param $(, const $const_param: usize)?> ::core::iter::IntoIterator for &'a mut $self { 364 | type Item = &'a mut $ty_param; 365 | type IntoIter = ::core::slice::IterMut<'a, T>; 366 | fn into_iter(self) -> Self::IntoIter { 367 | self.iter_mut() 368 | } 369 | } 370 | }; 371 | } 372 | pub(crate) use slice_iter; 373 | 374 | #[track_caller] 375 | const unsafe fn non_zero_usize(n: usize) -> NonZeroUsize { 376 | match NonZeroUsize::new(n) { 377 | Some(it) => it, 378 | None => unreachable(), 379 | } 380 | } 381 | 382 | #[track_caller] 383 | const unsafe fn unreachable() -> ! { 384 | match cfg!(debug_assertions) { 385 | true => unreachable(), 386 | false => unsafe { core::hint::unreachable_unchecked() }, 387 | } 388 | } 389 | 390 | /// Error returned in [`TryFrom`] implementations for reference conversions. 391 | #[derive(Debug, Clone, Copy)] 392 | pub struct TryFromSliceError(()); 393 | 394 | impl From for TryFromSliceError { 395 | fn from(value: Infallible) -> Self { 396 | match value {} 397 | } 398 | } 399 | 400 | impl fmt::Display for TryFromSliceError { 401 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 402 | f.write_str("could not convert slice to array") 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /src/mirror_std/cmp.rs: -------------------------------------------------------------------------------- 1 | //! There aren't that many implementations in [`std`]... 2 | 3 | use crate::{Array, Slice}; 4 | use core::cmp::Ordering; 5 | 6 | #[cfg(feature = "alloc")] 7 | use crate::Vec; 8 | 9 | impl PartialOrd for Slice 10 | where 11 | T: PartialOrd, 12 | { 13 | fn partial_cmp(&self, other: &Self) -> Option { 14 | <[_] as PartialOrd>::partial_cmp(self, other) 15 | } 16 | } 17 | 18 | impl Ord for Slice 19 | where 20 | T: Ord, 21 | { 22 | fn cmp(&self, other: &Self) -> Ordering { 23 | <[_] as Ord>::cmp(self, other) 24 | } 25 | } 26 | 27 | impl PartialOrd for Array 28 | where 29 | T: PartialOrd, 30 | { 31 | fn partial_cmp(&self, other: &Self) -> Option { 32 | <[_] as PartialOrd>::partial_cmp(self, other) 33 | } 34 | } 35 | impl Ord for Array 36 | where 37 | T: Ord, 38 | { 39 | fn cmp(&self, other: &Self) -> Ordering { 40 | <[_] as Ord>::cmp(self, other) 41 | } 42 | } 43 | 44 | #[cfg(feature = "alloc")] 45 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 46 | impl PartialOrd> for Vec 47 | where 48 | T: PartialOrd, 49 | { 50 | fn partial_cmp(&self, other: &Vec) -> Option { 51 | <[_] as PartialOrd>::partial_cmp(self, other) 52 | } 53 | } 54 | 55 | #[cfg(feature = "alloc")] 56 | impl Ord for Vec 57 | where 58 | T: Ord, 59 | { 60 | fn cmp(&self, other: &Self) -> Ordering { 61 | <[_] as Ord>::cmp(self, other) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/mirror_std/from.rs: -------------------------------------------------------------------------------- 1 | //! There should be an `impl` here that corresponds to every [`From`] 2 | //! implementation in [`std`] between: 3 | //! - `[T; N]` 4 | //! - `[T]` 5 | //! - [`Vec`](alloc::vec::Vec) 6 | //! 7 | //! Here's the methodology: 8 | //! - Use the `gen` tool in this repository to scrape rustdoc 9 | //! (HTML, not JSON - it's much easier) 10 | //! - Output the `test/from.rs` file in this repository. 11 | //! This is effectively a description of the standard library conversions. 12 | //! - Redact unstable items, and the [`std::net`] conversions. 13 | //! - Switch the types from the standard library to our libraries. 14 | //! - Write implementations _in the same order_ in this file. 15 | 16 | #[cfg(feature = "std")] 17 | use core::hash::Hash; 18 | #[cfg(feature = "std")] 19 | use std::{ 20 | collections::{HashMap, HashSet}, 21 | hash::RandomState, 22 | }; 23 | 24 | #[cfg(feature = "alloc")] 25 | use alloc::{ 26 | borrow::{Cow, ToOwned}, 27 | boxed::Box, 28 | collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}, 29 | rc::Rc, 30 | sync::Arc, 31 | }; 32 | 33 | #[cfg(feature = "alloc")] 34 | use crate::{Array, Slice, Vec}; 35 | 36 | #[cfg(feature = "alloc")] 37 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 38 | impl<'a, T> From<&'a Slice> for Cow<'a, Slice> 39 | where 40 | T: Clone, 41 | { 42 | fn from(value: &'a Slice) -> Self { 43 | Cow::Borrowed(value) 44 | } 45 | } 46 | 47 | #[cfg(feature = "alloc")] 48 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 49 | impl<'a, T> From<&'a Vec> for Cow<'a, Slice> 50 | where 51 | T: Clone, 52 | { 53 | fn from(value: &'a Vec) -> Self { 54 | Cow::Borrowed(value) 55 | } 56 | } 57 | 58 | #[cfg(feature = "alloc")] 59 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 60 | impl<'a, T> From>> for Vec 61 | where 62 | Slice: ToOwned>, 63 | { 64 | fn from(value: Cow<'a, Slice>) -> Self { 65 | value.into_owned() 66 | } 67 | } 68 | 69 | #[cfg(feature = "alloc")] 70 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 71 | impl<'a, T> From> for Cow<'a, Slice> 72 | where 73 | T: Clone, 74 | { 75 | fn from(value: Vec) -> Self { 76 | Cow::Owned(value) 77 | } 78 | } 79 | 80 | #[cfg(feature = "alloc")] 81 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 82 | impl<'a, const N: usize, T> From<&'a Array> for Cow<'a, Slice> 83 | where 84 | T: Clone, 85 | { 86 | fn from(value: &'a Array) -> Self { 87 | Cow::Borrowed(value.as_slice_ne()) 88 | } 89 | } 90 | 91 | #[cfg(feature = "std")] 92 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "std")))] 93 | impl From> for HashMap 94 | where 95 | K: Eq + Hash, 96 | { 97 | fn from(value: Array<(K, V), N>) -> Self { 98 | value.into_iter().collect() 99 | } 100 | } 101 | 102 | #[cfg(feature = "alloc")] 103 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 104 | impl From> for BTreeMap 105 | where 106 | K: Ord, 107 | { 108 | fn from(value: Array<(K, V), N>) -> Self { 109 | value.into_iter().collect() 110 | } 111 | } 112 | 113 | #[cfg(feature = "alloc")] 114 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 115 | impl From<&Slice> for Box> 116 | where 117 | T: Clone, 118 | { 119 | fn from(value: &Slice) -> Self { 120 | let value = Box::<[T]>::from(value.as_slice()); 121 | // Safety: 122 | // - transmuting is safe because #[repr(transparent)] 123 | // - already non-empty by construction 124 | unsafe { Box::>::from_raw(Box::into_raw(value) as *mut Slice) } 125 | } 126 | } 127 | 128 | #[cfg(feature = "alloc")] 129 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 130 | impl From<&Slice> for Rc> 131 | where 132 | T: Clone, 133 | { 134 | fn from(value: &Slice) -> Self { 135 | let src = Rc::<[T]>::from(value.as_slice()); 136 | // Safety: 137 | // - transmuting is safe because #[repr(transparent)] 138 | // - already non-empty by construction 139 | unsafe { Rc::>::from_raw(Rc::into_raw(src) as *mut Slice) } 140 | } 141 | } 142 | 143 | #[cfg(feature = "alloc")] 144 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 145 | impl From<&Slice> for Arc> 146 | where 147 | T: Clone, 148 | { 149 | fn from(value: &Slice) -> Self { 150 | let value = Arc::<[T]>::from(value.as_slice()); 151 | // Safety: 152 | // - transmuting is safe because #[repr(transparent)] 153 | // - already non-empty by construction 154 | unsafe { Arc::>::from_raw(Arc::into_raw(value) as *const Slice) } 155 | } 156 | } 157 | 158 | #[cfg(feature = "alloc")] 159 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 160 | impl From<&Slice> for Vec 161 | where 162 | T: Clone, 163 | { 164 | fn from(value: &Slice) -> Self { 165 | let value = alloc::vec::Vec::from(value.as_slice()); 166 | // Safety: 167 | // - already non-empty by construction 168 | unsafe { Self::new_unchecked(value) } 169 | } 170 | } 171 | 172 | #[cfg(feature = "alloc")] 173 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 174 | impl From<&mut Slice> for Vec 175 | where 176 | T: Clone, 177 | { 178 | fn from(value: &mut Slice) -> Self { 179 | let value = alloc::vec::Vec::from(value.as_slice()); 180 | // Safety: 181 | // - already non-empty by construction 182 | unsafe { Self::new_unchecked(value) } 183 | } 184 | } 185 | 186 | #[cfg(feature = "alloc")] 187 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 188 | impl From>> for Box> 189 | where 190 | T: Clone, 191 | { 192 | fn from(value: Cow<'_, Slice>) -> Self { 193 | value.into_owned().into_boxed_slice() 194 | } 195 | } 196 | 197 | #[cfg(feature = "alloc")] 198 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 199 | impl From>> for Vec { 200 | fn from(value: Box>) -> Self { 201 | let value = Box::into_raw(value); 202 | // Safety: 203 | // - transmuting is safe because #[repr(transparent)] 204 | let value = unsafe { Box::from_raw(value as *mut [T]) }; 205 | let value = alloc::vec::Vec::from(value); 206 | // Safety: 207 | // - already non-empty by construction 208 | unsafe { Self::new_unchecked(value) } 209 | } 210 | } 211 | 212 | #[cfg(feature = "alloc")] 213 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 214 | impl From> for Box> { 215 | fn from(value: Vec) -> Self { 216 | value.into_boxed_slice() 217 | } 218 | } 219 | 220 | #[cfg(feature = "alloc")] 221 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 222 | impl From> for Rc> { 223 | fn from(value: Vec) -> Self { 224 | value.into_boxed_slice().into() 225 | } 226 | } 227 | 228 | #[cfg(feature = "alloc")] 229 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 230 | impl From> for Arc> { 231 | fn from(value: Vec) -> Self { 232 | value.into_boxed_slice().into() 233 | } 234 | } 235 | 236 | #[cfg(feature = "alloc")] 237 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 238 | impl From<&Array> for Vec 239 | where 240 | T: Clone, 241 | { 242 | fn from(value: &Array) -> Self { 243 | value.as_slice_ne().into() 244 | } 245 | } 246 | 247 | #[cfg(feature = "alloc")] 248 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 249 | impl From<&mut Array> for Vec 250 | where 251 | T: Clone, 252 | { 253 | fn from(value: &mut Array) -> Self { 254 | value.as_slice_ne().into() 255 | } 256 | } 257 | 258 | #[cfg(feature = "alloc")] 259 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 260 | impl From> for Box> { 261 | fn from(value: Array) -> Self { 262 | let value = Box::<[T]>::from(value.into_array()); 263 | // Safety: 264 | // - transmuting is safe because #[repr(transparent)] 265 | unsafe { Box::>::from_raw(Box::into_raw(value) as *mut Slice) } 266 | } 267 | } 268 | 269 | #[cfg(feature = "std")] 270 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "std")))] 271 | impl From> for HashSet 272 | where 273 | T: Eq + Hash, 274 | { 275 | fn from(value: Array) -> Self { 276 | value.into_iter().collect() 277 | } 278 | } 279 | 280 | #[cfg(feature = "alloc")] 281 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 282 | impl From> for BTreeSet 283 | where 284 | T: Ord, 285 | { 286 | fn from(value: Array) -> Self { 287 | value.into_iter().collect() 288 | } 289 | } 290 | 291 | #[cfg(feature = "alloc")] 292 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 293 | impl From> for BinaryHeap 294 | where 295 | T: Ord, 296 | { 297 | fn from(value: Array) -> Self { 298 | value.into_iter().collect() 299 | } 300 | } 301 | 302 | #[cfg(feature = "alloc")] 303 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 304 | impl From> for LinkedList { 305 | fn from(value: Array) -> Self { 306 | value.into_iter().collect() 307 | } 308 | } 309 | 310 | #[cfg(feature = "alloc")] 311 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 312 | impl From> for VecDeque { 313 | fn from(value: Array) -> Self { 314 | value.into_iter().collect() 315 | } 316 | } 317 | 318 | #[cfg(feature = "alloc")] 319 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 320 | impl From> for Rc> { 321 | fn from(value: Array) -> Self { 322 | let value = Rc::<[T]>::from(value.into_array()); 323 | let value = Rc::into_raw(value); 324 | // Safety: 325 | // - transmuting is safe because #[repr(transparent)] 326 | unsafe { Rc::from_raw(value as *const Slice) } 327 | } 328 | } 329 | 330 | #[cfg(feature = "alloc")] 331 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 332 | impl From> for Arc> { 333 | fn from(value: Array) -> Self { 334 | let value = Arc::<[T]>::from(value.into_array()); 335 | // Safety: 336 | // - transmuting is safe because #[repr(transparent)] 337 | unsafe { Arc::>::from_raw(Arc::into_raw(value) as *const Slice) } 338 | } 339 | } 340 | 341 | #[cfg(feature = "alloc")] 342 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 343 | impl From> for Vec { 344 | fn from(value: Array) -> Self { 345 | let value = alloc::vec::Vec::from(value.into_array()); 346 | // Safety: 347 | // - already non-empty by construction 348 | unsafe { Vec::new_unchecked(value) } 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/mirror_std/partial_eq.rs: -------------------------------------------------------------------------------- 1 | //! There should be an `impl` here that corresponds to every [`PartialEq`] 2 | //! implementation in [`std`] between: 3 | //! - `[T; N]` 4 | //! - `[T]` 5 | //! - [`Vec`](alloc::vec::Vec) 6 | //! 7 | //! Here's the methodology: 8 | //! - Use the `gen` tool in this repository to scrape rustdoc 9 | //! (HTML, not JSON - it's much easier) 10 | //! - Output the `test/try_from.rs` file in this repository. 11 | //! This is effectively a description of the standard library conversions. 12 | //! - Redact unstable items, and implementations we can't do because we're not std. 13 | //! - Switch the types from the standard library to our libraries. 14 | //! - Write implementations _in the same order_ in this file. 15 | 16 | #[cfg(feature = "alloc")] 17 | use crate::Vec; 18 | use crate::{Array, Slice}; 19 | #[cfg(feature = "alloc")] 20 | use alloc::{borrow::Cow, collections::VecDeque}; 21 | 22 | impl PartialEq> for Slice 23 | where 24 | A: PartialEq, 25 | { 26 | fn eq(&self, other: &Slice) -> bool { 27 | <[_] as PartialEq<[_]>>::eq(self, other) 28 | } 29 | } 30 | 31 | impl PartialEq<&Slice> for Array 32 | where 33 | A: PartialEq, 34 | { 35 | fn eq(&self, other: &&Slice) -> bool { 36 | <[_] as PartialEq<[_]>>::eq(self, other) 37 | } 38 | } 39 | 40 | impl PartialEq<&mut Slice> for Array 41 | where 42 | A: PartialEq, 43 | { 44 | fn eq(&self, other: &&mut Slice) -> bool { 45 | <[_] as PartialEq<[_]>>::eq(self, other) 46 | } 47 | } 48 | 49 | impl PartialEq> for &Slice 50 | where 51 | B: PartialEq, 52 | { 53 | fn eq(&self, other: &Array) -> bool { 54 | <[_] as PartialEq<[_]>>::eq(self, other) 55 | } 56 | } 57 | 58 | impl PartialEq> for &mut Slice 59 | where 60 | B: PartialEq, 61 | { 62 | fn eq(&self, other: &Array) -> bool { 63 | <[_] as PartialEq<[_]>>::eq(self, other) 64 | } 65 | } 66 | 67 | impl PartialEq> for Slice 68 | where 69 | B: PartialEq, 70 | { 71 | fn eq(&self, other: &Array) -> bool { 72 | <[_] as PartialEq<[_]>>::eq(self, other) 73 | } 74 | } 75 | 76 | impl PartialEq> for Array 77 | where 78 | A: PartialEq, 79 | { 80 | fn eq(&self, other: &Array) -> bool { 81 | <[_] as PartialEq<[_]>>::eq(self, other) 82 | } 83 | } 84 | 85 | impl PartialEq> for Array 86 | where 87 | A: PartialEq, 88 | { 89 | fn eq(&self, other: &Slice) -> bool { 90 | <[_] as PartialEq<[_]>>::eq(self, other) 91 | } 92 | } 93 | 94 | #[cfg(feature = "alloc")] 95 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 96 | impl PartialEq<&Slice> for Cow<'_, Slice> 97 | where 98 | T: PartialEq + Clone, 99 | { 100 | fn eq(&self, other: &&Slice) -> bool { 101 | <[_] as PartialEq<[_]>>::eq(self, other) 102 | } 103 | } 104 | 105 | #[cfg(feature = "alloc")] 106 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 107 | impl PartialEq<&mut Slice> for Cow<'_, Slice> 108 | where 109 | T: PartialEq + Clone, 110 | { 111 | fn eq(&self, other: &&mut Slice) -> bool { 112 | <[_] as PartialEq<[_]>>::eq(self, other) 113 | } 114 | } 115 | 116 | #[cfg(feature = "alloc")] 117 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 118 | impl PartialEq<&Slice> for VecDeque 119 | where 120 | T: PartialEq, 121 | { 122 | fn eq(&self, other: &&Slice) -> bool { 123 | if self.len() != other.len_ne().get() { 124 | return false; 125 | } 126 | let (sa, sb) = self.as_slices(); 127 | let (oa, ob) = other[..].split_at(sa.len()); 128 | sa == oa && sb == ob 129 | } 130 | } 131 | 132 | #[cfg(feature = "alloc")] 133 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 134 | impl PartialEq<&Slice> for Vec 135 | where 136 | T: PartialEq, 137 | { 138 | fn eq(&self, other: &&Slice) -> bool { 139 | <[_] as PartialEq<[_]>>::eq(self, other) 140 | } 141 | } 142 | 143 | #[cfg(feature = "alloc")] 144 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 145 | impl PartialEq<&mut Slice> for VecDeque 146 | where 147 | T: PartialEq, 148 | { 149 | fn eq(&self, other: &&mut Slice) -> bool { 150 | PartialEq::<&Slice>::eq(self, &&**other) 151 | } 152 | } 153 | 154 | #[cfg(feature = "alloc")] 155 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 156 | impl PartialEq<&mut Slice> for Vec 157 | where 158 | T: PartialEq, 159 | { 160 | fn eq(&self, other: &&mut Slice) -> bool { 161 | <[_] as PartialEq<[_]>>::eq(self, other) 162 | } 163 | } 164 | 165 | #[cfg(feature = "alloc")] 166 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 167 | impl PartialEq> for Vec 168 | where 169 | T: PartialEq, 170 | { 171 | fn eq(&self, other: &Slice) -> bool { 172 | <[_] as PartialEq<[_]>>::eq(self, other) 173 | } 174 | } 175 | 176 | #[cfg(feature = "alloc")] 177 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 178 | impl PartialEq> for &Slice 179 | where 180 | T: PartialEq, 181 | { 182 | fn eq(&self, other: &Vec) -> bool { 183 | <[_] as PartialEq<[_]>>::eq(self, other) 184 | } 185 | } 186 | 187 | #[cfg(feature = "alloc")] 188 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 189 | impl PartialEq> for &mut Slice 190 | where 191 | T: PartialEq, 192 | { 193 | fn eq(&self, other: &Vec) -> bool { 194 | <[_] as PartialEq<[_]>>::eq(self, other) 195 | } 196 | } 197 | 198 | #[cfg(feature = "alloc")] 199 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 200 | impl PartialEq> for Cow<'_, Slice> 201 | where 202 | T: PartialEq + Clone, 203 | { 204 | fn eq(&self, other: &Vec) -> bool { 205 | <[_] as PartialEq<[_]>>::eq(self, other) 206 | } 207 | } 208 | 209 | #[cfg(feature = "alloc")] 210 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 211 | impl PartialEq> for Slice 212 | where 213 | T: PartialEq, 214 | { 215 | fn eq(&self, other: &Vec) -> bool { 216 | <[_] as PartialEq<[_]>>::eq(self, other) 217 | } 218 | } 219 | 220 | #[cfg(feature = "alloc")] 221 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 222 | impl PartialEq<&Array> for VecDeque 223 | where 224 | T: PartialEq, 225 | { 226 | fn eq(&self, other: &&Array) -> bool { 227 | PartialEq::<&Slice>::eq(self, &&***other) 228 | } 229 | } 230 | 231 | #[cfg(feature = "alloc")] 232 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 233 | impl PartialEq<&Array> for Vec 234 | where 235 | T: PartialEq, 236 | { 237 | fn eq(&self, other: &&Array) -> bool { 238 | <[_] as PartialEq<[_]>>::eq(self, other) 239 | } 240 | } 241 | 242 | #[cfg(feature = "alloc")] 243 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 244 | impl PartialEq<&mut Array> for VecDeque 245 | where 246 | T: PartialEq, 247 | { 248 | fn eq(&self, other: &&mut Array) -> bool { 249 | PartialEq::<&Slice>::eq(self, &&***other) 250 | } 251 | } 252 | 253 | #[cfg(feature = "alloc")] 254 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 255 | impl PartialEq> for VecDeque 256 | where 257 | T: PartialEq, 258 | { 259 | fn eq(&self, other: &Array) -> bool { 260 | PartialEq::<&Slice>::eq(self, &&**other) 261 | } 262 | } 263 | 264 | #[cfg(feature = "alloc")] 265 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 266 | impl PartialEq> for Vec 267 | where 268 | T: PartialEq, 269 | { 270 | fn eq(&self, other: &Array) -> bool { 271 | <[_] as PartialEq<[_]>>::eq(self, other) 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/mirror_std/try_from.rs: -------------------------------------------------------------------------------- 1 | //! There should be an `impl` here that corresponds to every [`TryFrom`] 2 | //! implementation in [`std`] between: 3 | //! - `[T; N]` 4 | //! - `[T]` 5 | //! - [`Vec`](alloc::vec::Vec) 6 | //! 7 | //! Here's the methodology: 8 | //! - Use the `gen` tool in this repository to scrape rustdoc 9 | //! (HTML, not JSON - it's much easier) 10 | //! - Output the `test/try_from.rs` file in this repository. 11 | //! This is effectively a description of the standard library conversions. 12 | //! - Redact unstable items, and conversions we can't implement because we're 13 | //! not std. 14 | //! - Switch the types from the standard library to our libraries. 15 | //! - Write implementations _in the same order_ in this file. 16 | 17 | #[cfg(feature = "alloc")] 18 | use crate::Vec; 19 | use crate::{Array, Slice, TryFromSliceError}; 20 | #[cfg(feature = "alloc")] 21 | use alloc::boxed::Box; 22 | // use alloc::{rc::Rc, sync::Arc}; 23 | 24 | impl<'a, T, const N: usize> TryFrom<&'a Slice> for &'a Array { 25 | type Error = TryFromSliceError; 26 | 27 | fn try_from(value: &'a Slice) -> Result { 28 | value 29 | .as_slice() 30 | .try_into() 31 | .ok() 32 | .and_then(Array::new_ref) 33 | .ok_or(TryFromSliceError(())) 34 | } 35 | } 36 | 37 | impl<'a, T, const N: usize> TryFrom<&'a mut Slice> for &'a mut Array { 38 | type Error = TryFromSliceError; 39 | 40 | fn try_from(value: &'a mut Slice) -> Result { 41 | value 42 | .as_mut_slice() 43 | .try_into() 44 | .ok() 45 | .and_then(Array::new_mut) 46 | .ok_or(TryFromSliceError(())) 47 | } 48 | } 49 | 50 | // impl TryFrom>> for Arc> { 51 | // type Error = (); 52 | 53 | // fn try_from(value: Arc>) -> Result { 54 | // todo!() 55 | // } 56 | // } 57 | 58 | #[cfg(feature = "alloc")] 59 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 60 | impl TryFrom> for Array { 61 | type Error = Vec; 62 | 63 | fn try_from(value: Vec) -> Result { 64 | // Safety: 65 | // - already non-empty by construction 66 | match value.into_vec().try_into() { 67 | Ok(it) => Ok(unsafe { Array::new_unchecked(it) }), 68 | Err(it) => Err(unsafe { Vec::new_unchecked(it) }), 69 | } 70 | } 71 | } 72 | 73 | impl TryFrom<&Slice> for Array 74 | where 75 | T: Copy, 76 | { 77 | type Error = TryFromSliceError; 78 | 79 | fn try_from(value: &Slice) -> Result { 80 | // Safety: 81 | // - already non-empty by construction 82 | match value.as_slice().try_into() { 83 | Ok(it) => Ok(unsafe { Array::new_unchecked(it) }), 84 | Err(_) => Err(TryFromSliceError(())), 85 | } 86 | } 87 | } 88 | impl TryFrom<&mut Slice> for Array 89 | where 90 | T: Copy, 91 | { 92 | type Error = TryFromSliceError; 93 | 94 | fn try_from(value: &mut Slice) -> Result { 95 | // Safety: 96 | // - already non-empty by construction 97 | match value.as_mut_slice().try_into() { 98 | Ok(it) => Ok(unsafe { Array::new_unchecked(it) }), 99 | Err(_) => Err(TryFromSliceError(())), 100 | } 101 | } 102 | } 103 | 104 | #[cfg(feature = "alloc")] 105 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 106 | impl TryFrom>> for Box> { 107 | type Error = Box>; 108 | 109 | fn try_from(value: Box>) -> Result { 110 | // Safety: 111 | // - already checked len 112 | match value.len_ne().get() == N { 113 | true => Ok(unsafe { boxed_slice_as_array_unchecked(value) }), 114 | false => Err(value), 115 | } 116 | } 117 | } 118 | 119 | // impl TryFrom>> for Rc> { 120 | // type Error = (); 121 | 122 | // fn try_from(value: Rc>) -> Result { 123 | // todo!() 124 | // } 125 | // } 126 | 127 | #[cfg(feature = "alloc")] 128 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 129 | impl TryFrom> for Box> { 130 | type Error = Vec; 131 | 132 | fn try_from(value: Vec) -> Result { 133 | // Safety: 134 | // - already checked len 135 | match value.len() == N { 136 | true => Ok(unsafe { boxed_slice_as_array_unchecked(value.into_boxed_slice()) }), 137 | false => Err(value), 138 | } 139 | } 140 | } 141 | 142 | /// Casts a boxed slice to a boxed array. 143 | /// 144 | /// # Safety 145 | /// 146 | /// `boxed_slice.len()` must be exactly `N`. 147 | #[cfg(feature = "alloc")] 148 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 149 | unsafe fn boxed_slice_as_array_unchecked( 150 | boxed_slice: Box>, 151 | ) -> Box> { 152 | debug_assert_eq!(boxed_slice.len(), N); 153 | 154 | let ptr = Box::into_raw(boxed_slice); 155 | unsafe { Box::from_raw(ptr as *mut Array) } 156 | } 157 | -------------------------------------------------------------------------------- /src/proptest1.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "alloc")] 2 | use core::fmt::Debug; 3 | 4 | use crate::{Slice, Vec}; 5 | 6 | use proptest1::{ 7 | arbitrary::Arbitrary, 8 | sample::SizeRange, 9 | strategy::{FilterMap, Map, Strategy as _}, 10 | }; 11 | 12 | impl Arbitrary for Vec 13 | where 14 | T: Arbitrary + Debug, 15 | { 16 | type Parameters = (SizeRange, ::Parameters); 17 | 18 | fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { 19 | alloc::vec::Vec::::arbitrary_with(args) 20 | .prop_filter_map("vec was empty", |it| Vec::new(it).ok()) 21 | } 22 | 23 | type Strategy = FilterMap< 24 | as Arbitrary>::Strategy, 25 | fn(alloc::vec::Vec) -> Option>, 26 | >; 27 | } 28 | 29 | impl Arbitrary for Box> 30 | where 31 | T: Arbitrary + Debug, 32 | { 33 | type Parameters = (SizeRange, ::Parameters); 34 | 35 | fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { 36 | Vec::arbitrary_with(args).prop_map(Into::into) 37 | } 38 | 39 | type Strategy = Map< as Arbitrary>::Strategy, fn(Vec) -> Box>>; 40 | } 41 | -------------------------------------------------------------------------------- /src/quickcheck1.rs: -------------------------------------------------------------------------------- 1 | use crate::{Slice, Vec}; 2 | use quickcheck1::Arbitrary; 3 | 4 | impl Arbitrary for Vec 5 | where 6 | T: Arbitrary, 7 | { 8 | fn arbitrary(g: &mut quickcheck1::Gen) -> Self { 9 | let mut it = Vec::of(T::arbitrary(g)); 10 | it.extend(alloc::vec::Vec::arbitrary(g)); 11 | it 12 | } 13 | fn shrink(&self) -> Box> { 14 | let raw = self.clone().into_vec(); 15 | Box::new(Arbitrary::shrink(&raw).flat_map(Vec::new)) 16 | } 17 | } 18 | 19 | impl Arbitrary for Box> 20 | where 21 | T: Arbitrary, 22 | { 23 | fn arbitrary(g: &mut quickcheck1::Gen) -> Self { 24 | let mut it = Vec::of(T::arbitrary(g)); 25 | it.extend(alloc::vec::Vec::arbitrary(g)); 26 | it.into_boxed_slice() 27 | } 28 | fn shrink(&self) -> Box> { 29 | let raw = Vec::from(self.clone()); 30 | Box::new(Arbitrary::shrink(&raw).map(Self::from)) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/schemars08.rs: -------------------------------------------------------------------------------- 1 | use crate::{Array, Slice, Vec}; 2 | use schemars08::{ 3 | gen::SchemaGenerator, 4 | schema::{ArrayValidation, InstanceType, Schema, SchemaObject, SingleOrVec}, 5 | JsonSchema, 6 | }; 7 | 8 | impl JsonSchema for Vec 9 | where 10 | T: JsonSchema, 11 | { 12 | fn schema_name() -> String { 13 | format!("NonEmpty_Array_of_{}", T::schema_name()) 14 | } 15 | 16 | fn json_schema(gen: &mut SchemaGenerator) -> Schema { 17 | Schema::Object(SchemaObject { 18 | instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))), 19 | array: Some(Box::new(ArrayValidation { 20 | items: Some(SingleOrVec::Single(Box::new(gen.subschema_for::()))), 21 | min_items: Some(1), 22 | ..Default::default() 23 | })), 24 | ..Default::default() 25 | }) 26 | } 27 | } 28 | 29 | impl JsonSchema for Box> 30 | where 31 | T: JsonSchema, 32 | { 33 | fn schema_name() -> String { 34 | Vec::::schema_name() 35 | } 36 | 37 | fn json_schema(gen: &mut schemars08::gen::SchemaGenerator) -> Schema { 38 | Vec::::json_schema(gen) 39 | } 40 | } 41 | 42 | impl JsonSchema for Array 43 | where 44 | T: JsonSchema, 45 | { 46 | fn schema_name() -> String { 47 | format!("Array_of_{}_of_{}", N, T::schema_name()) 48 | } 49 | 50 | fn json_schema(gen: &mut schemars08::gen::SchemaGenerator) -> Schema { 51 | Schema::Object(SchemaObject { 52 | instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))), 53 | array: Some(Box::new(ArrayValidation { 54 | items: Some(SingleOrVec::Single(Box::new(gen.subschema_for::()))), 55 | min_items: Some(u32::try_from(N).unwrap_or(u32::MAX)), 56 | max_items: Some(u32::try_from(N).unwrap_or(u32::MAX)), 57 | ..Default::default() 58 | })), 59 | ..Default::default() 60 | }) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/serde1.rs: -------------------------------------------------------------------------------- 1 | use serde1::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; 2 | 3 | use crate::Slice; 4 | #[cfg(feature = "alloc")] 5 | use { 6 | crate::{Error, Vec}, 7 | alloc::boxed::Box, 8 | }; 9 | 10 | impl<'de: 'a, 'a> Deserialize<'de> for &'a Slice { 11 | fn deserialize(deserializer: D) -> Result 12 | where 13 | D: Deserializer<'de>, 14 | { 15 | <&Slice>::try_from(<&[u8]>::deserialize(deserializer)?).map_err(D::Error::custom) 16 | } 17 | } 18 | 19 | impl Serialize for Slice 20 | where 21 | T: Serialize, 22 | { 23 | fn serialize(&self, serializer: S) -> Result 24 | where 25 | S: Serializer, 26 | { 27 | self.as_slice().serialize(serializer) 28 | } 29 | } 30 | 31 | #[cfg(feature = "alloc")] 32 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 33 | impl<'de, T> Deserialize<'de> for Box> 34 | where 35 | T: Deserialize<'de>, 36 | { 37 | fn deserialize(deserializer: D) -> Result 38 | where 39 | D: Deserializer<'de>, 40 | { 41 | >>::try_from(>::deserialize(deserializer)?).map_err(D::Error::custom) 42 | } 43 | } 44 | 45 | #[cfg(feature = "alloc")] 46 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 47 | impl<'de, T> Deserialize<'de> for Vec 48 | where 49 | T: Deserialize<'de>, 50 | { 51 | fn deserialize(deserializer: D) -> Result 52 | where 53 | D: Deserializer<'de>, 54 | { 55 | Vec::new(alloc::vec::Vec::deserialize(deserializer)?) 56 | .map_err(|_| D::Error::custom(Error(()))) 57 | } 58 | } 59 | #[cfg(feature = "alloc")] 60 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 61 | impl Serialize for Vec 62 | where 63 | T: Serialize, 64 | { 65 | fn serialize(&self, serializer: S) -> Result 66 | where 67 | S: Serializer, 68 | { 69 | self.as_vec().serialize(serializer) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/slice.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | num::NonZeroUsize, 3 | ops::{Deref, DerefMut}, 4 | slice, 5 | }; 6 | 7 | use crate::{NonEmpty, Slice}; 8 | 9 | impl Eq for NonEmpty<[T]> where T: Eq {} 10 | 11 | macro_rules! forward { 12 | ($($(#[$meta:meta])* pub const fn $ident:ident(&self) -> $ty:ty);* $(;)?) => { 13 | $( 14 | $(#[$meta])* 15 | pub const fn $ident(&self) -> $ty { 16 | match self.as_slice().$ident() { 17 | Some(it) => it, 18 | // Safety: 19 | // - cannot create empty slice without `unsafe` 20 | None => unsafe { crate::unreachable() }, 21 | } 22 | } 23 | )* 24 | } 25 | } 26 | macro_rules! forward_mut { 27 | ($($(#[$meta:meta])* pub fn $ident:ident(&mut self) -> $ty:ty);* $(;)?) => { 28 | $( 29 | $(#[$meta])* 30 | pub fn $ident(&mut self) -> $ty { 31 | match self.as_mut_slice().$ident() { 32 | Some(it) => it, 33 | // Safety: 34 | // - cannot create empty slice without `unsafe` 35 | None => unsafe { crate::unreachable() }, 36 | } 37 | } 38 | )* 39 | } 40 | } 41 | 42 | /// [`Slice`] methods 43 | impl Slice { 44 | /////////// 45 | // Creation 46 | /////////// 47 | 48 | crate::map_non_empty! { 49 | const 50 | /// Create a new [`NonEmpty`] slice 51 | new(&[T]) -> &Self: Self::new_unchecked; 52 | 53 | /// Create a new [`NonEmpty`] slice 54 | new_mut(&mut [T]) -> &mut Self: Self::new_mut_unchecked; 55 | } 56 | crate::transmuting! { 57 | const 58 | /// Create a new [`NonEmpty`] slice 59 | new_unchecked(&[T]) -> &Self; 60 | 61 | /// Create a new [`NonEmpty`] slice 62 | new_mut_unchecked(&mut [T]) -> &mut Self; 63 | } 64 | 65 | //////////// 66 | // Utilities 67 | //////////// 68 | 69 | /// Create a [`NonEmpty`] slice of a single element 70 | pub const fn of(item: &T) -> &Self { 71 | let shared = slice::from_ref(item); 72 | // Safety: 73 | // - len is 1 74 | unsafe { Self::new_unchecked(shared) } 75 | } 76 | /// Create a [`NonEmpty`] slice of a single element 77 | pub fn of_mut(item: &mut T) -> &mut Self { 78 | let shared = slice::from_mut(item); 79 | // Safety: 80 | // - len is 1 81 | unsafe { Self::new_mut_unchecked(shared) } 82 | } 83 | const fn check(&self) { 84 | debug_assert!(!self.inner.is_empty()); 85 | } 86 | 87 | /////////////////// 88 | // Inner references 89 | /////////////////// 90 | 91 | /// Returns a [`primitive slice`](primitive@slice). 92 | pub const fn as_slice(&self) -> &[T] { 93 | self.check(); 94 | &self.inner 95 | } 96 | /// Returns a [`primitive slice`](primitive@slice). 97 | pub fn as_mut_slice(&mut self) -> &mut [T] { 98 | self.check(); 99 | &mut self.inner 100 | } 101 | 102 | ////////////////// 103 | // Shimmed methods 104 | ////////////////// 105 | 106 | /// Returns the known non-zero length. 107 | pub const fn len_ne(&self) -> NonZeroUsize { 108 | unsafe { crate::non_zero_usize(self.inner.len()) } 109 | } 110 | forward! { 111 | /// Returns the first element, guaranteed. 112 | pub const fn first(&self) -> &T; 113 | /// Returns the first element, guaranteed, and the rest of the elements. 114 | pub const fn split_first(&self) -> (&T, &[T]); 115 | /// Returns the last element, guaranteed, and the rest of the elements. 116 | pub const fn split_last(&self) -> (&T, &[T]); 117 | /// Returns the last element, guaranteed. 118 | pub const fn last(&self) -> &T; 119 | } 120 | forward_mut! { 121 | /// Returns the first element, guaranteed. 122 | pub fn first_mut(&mut self) -> &mut T ; 123 | /// Returns the first element, guaranteed, and the rest of the elements. 124 | pub fn split_first_mut(&mut self) -> (&mut T, &mut [T]); 125 | /// Returns the last element, guaranteed, and the rest of the elements. 126 | pub fn split_last_mut(&mut self) -> (&mut T, &mut [T]); 127 | /// Returns the last element, guaranteed. 128 | pub fn last_mut(&mut self) -> &mut T; 129 | } 130 | } 131 | 132 | /// Known non-empty iterators for [`Slice`]. 133 | impl Slice { 134 | pub fn iter_ne(&self) -> NonEmpty> { 135 | NonEmpty { inner: self.iter() } 136 | } 137 | pub fn iter_mut_ne(&mut self) -> NonEmpty> { 138 | NonEmpty { 139 | inner: self.iter_mut(), 140 | } 141 | } 142 | 143 | #[cfg(feature = "alloc")] 144 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 145 | pub fn into_iter_ne(self: alloc::boxed::Box) -> NonEmpty> { 146 | crate::Vec::from(self).into_iter_ne() 147 | } 148 | } 149 | 150 | /// [`Slice`] to [`primitive slice`](primitive@slice) 151 | impl Deref for Slice { 152 | type Target = [T]; 153 | 154 | fn deref(&self) -> &Self::Target { 155 | self.as_slice() 156 | } 157 | } 158 | 159 | /// [`Slice`] to [`primitive slice`](primitive@slice) 160 | impl DerefMut for Slice { 161 | fn deref_mut(&mut self) -> &mut Self::Target { 162 | self.as_mut_slice() 163 | } 164 | } 165 | 166 | crate::as_ref_as_mut! { 167 | for Slice as [T]; 168 | for Slice as Self; 169 | } 170 | 171 | crate::borrow_borrow_mut! { 172 | for Slice as [T]; 173 | } 174 | 175 | crate::slice_iter! { 176 | for Slice 177 | } 178 | 179 | #[cfg(feature = "alloc")] 180 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 181 | impl IntoIterator for alloc::boxed::Box> { 182 | type Item = T; 183 | 184 | type IntoIter = alloc::vec::IntoIter; 185 | 186 | fn into_iter(self) -> Self::IntoIter { 187 | crate::Vec::::from(self).into_iter() 188 | } 189 | } 190 | 191 | #[cfg(feature = "alloc")] 192 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 193 | impl alloc::borrow::ToOwned for Slice 194 | where 195 | T: Clone, 196 | { 197 | type Owned = crate::Vec; 198 | 199 | fn to_owned(&self) -> Self::Owned { 200 | self.into() 201 | } 202 | } 203 | 204 | mod partial_eq_std { 205 | use super::*; 206 | 207 | impl PartialEq<[U]> for Slice 208 | where 209 | T: PartialEq, 210 | { 211 | fn eq(&self, other: &[U]) -> bool { 212 | <[_] as PartialEq<[_]>>::eq(self, other) 213 | } 214 | } 215 | impl PartialEq<[U; N]> for Slice 216 | where 217 | T: PartialEq, 218 | { 219 | fn eq(&self, other: &[U; N]) -> bool { 220 | <[_] as PartialEq<[_]>>::eq(self, other) 221 | } 222 | } 223 | #[cfg(feature = "alloc")] 224 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 225 | impl PartialEq> for Slice 226 | where 227 | T: PartialEq, 228 | { 229 | fn eq(&self, other: &alloc::vec::Vec) -> bool { 230 | <[_] as PartialEq<[_]>>::eq(self, other) 231 | } 232 | } 233 | 234 | // converse 235 | //--------- 236 | 237 | impl PartialEq> for [U] 238 | where 239 | U: PartialEq, 240 | { 241 | fn eq(&self, other: &Slice) -> bool { 242 | <[_] as PartialEq<[_]>>::eq(self, other) 243 | } 244 | } 245 | impl PartialEq> for [U; N] 246 | where 247 | U: PartialEq, 248 | { 249 | fn eq(&self, other: &Slice) -> bool { 250 | <[_] as PartialEq<[_]>>::eq(self, other) 251 | } 252 | } 253 | #[cfg(feature = "alloc")] 254 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 255 | impl PartialEq> for alloc::vec::Vec 256 | where 257 | U: PartialEq, 258 | { 259 | fn eq(&self, other: &Slice) -> bool { 260 | <[_] as PartialEq<[_]>>::eq(self, other) 261 | } 262 | } 263 | } 264 | 265 | mod cmp_std { 266 | use core::cmp::Ordering; 267 | 268 | use super::*; 269 | 270 | impl PartialOrd<[T]> for Slice 271 | where 272 | T: PartialOrd, 273 | { 274 | fn partial_cmp(&self, other: &[T]) -> Option { 275 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 276 | } 277 | } 278 | impl PartialOrd<[T; N]> for Slice 279 | where 280 | T: PartialOrd, 281 | { 282 | fn partial_cmp(&self, other: &[T; N]) -> Option { 283 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 284 | } 285 | } 286 | #[cfg(feature = "alloc")] 287 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 288 | impl PartialOrd> for Slice 289 | where 290 | T: PartialOrd, 291 | { 292 | fn partial_cmp(&self, other: &alloc::vec::Vec) -> Option { 293 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 294 | } 295 | } 296 | 297 | // converse 298 | //--------- 299 | 300 | impl PartialOrd> for [T] 301 | where 302 | T: PartialOrd, 303 | { 304 | fn partial_cmp(&self, other: &Slice) -> Option { 305 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 306 | } 307 | } 308 | impl PartialOrd> for [T; N] 309 | where 310 | T: PartialOrd, 311 | { 312 | fn partial_cmp(&self, other: &Slice) -> Option { 313 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 314 | } 315 | } 316 | #[cfg(feature = "alloc")] 317 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 318 | impl PartialOrd> for alloc::vec::Vec 319 | where 320 | T: PartialOrd, 321 | { 322 | fn partial_cmp(&self, other: &Slice) -> Option { 323 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 324 | } 325 | } 326 | } 327 | 328 | #[cfg(feature = "alloc")] 329 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 330 | impl Clone for alloc::boxed::Box> 331 | where 332 | T: Clone, 333 | { 334 | fn clone(&self) -> Self { 335 | let src = self.to_vec(); 336 | // Safety: 337 | // - Src is non-empty by construction 338 | unsafe { crate::Vec::new_unchecked(src) }.into_boxed_slice() 339 | } 340 | } 341 | 342 | mod convert_std { 343 | #[cfg(feature = "alloc")] 344 | use alloc::boxed::Box; 345 | 346 | use crate::Error; 347 | 348 | use super::*; 349 | 350 | impl<'a, T> TryFrom<&'a [T]> for &'a Slice { 351 | type Error = Error; 352 | 353 | fn try_from(value: &'a [T]) -> Result { 354 | Slice::new(value).ok_or(Error(())) 355 | } 356 | } 357 | impl<'a, T> TryFrom<&'a mut [T]> for &'a mut Slice { 358 | type Error = Error; 359 | 360 | fn try_from(value: &'a mut [T]) -> Result { 361 | Slice::new_mut(value).ok_or(Error(())) 362 | } 363 | } 364 | 365 | #[cfg(feature = "alloc")] 366 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 367 | impl TryFrom> for Box> { 368 | type Error = Error; 369 | 370 | fn try_from(value: Box<[T]>) -> Result { 371 | match crate::Vec::new(value.into_vec()) { 372 | Ok(it) => Ok(it.into_boxed_slice()), 373 | Err(_) => Err(Error(())), 374 | } 375 | } 376 | } 377 | 378 | impl<'a, T> From<&'a Slice> for &'a [T] { 379 | fn from(value: &'a Slice) -> Self { 380 | value.as_slice() 381 | } 382 | } 383 | impl<'a, T> From<&'a mut Slice> for &'a mut [T] { 384 | fn from(value: &'a mut Slice) -> Self { 385 | value.as_mut_slice() 386 | } 387 | } 388 | #[cfg(feature = "alloc")] 389 | #[cfg_attr(do_doc_cfg, doc(cfg(feature = "alloc")))] 390 | impl From>> for Box<[T]> { 391 | fn from(value: Box>) -> Self { 392 | crate::Vec::from(value).into_vec().into_boxed_slice() 393 | } 394 | } 395 | } 396 | -------------------------------------------------------------------------------- /src/vec.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | mem::MaybeUninit, 3 | num::NonZeroUsize, 4 | ops::{Deref, DerefMut}, 5 | }; 6 | 7 | use alloc::{boxed::Box, collections::TryReserveError}; 8 | 9 | use crate::{NonEmpty, Slice, Vec}; 10 | 11 | impl Eq for NonEmpty> where T: Eq {} 12 | impl PartialEq> for Vec 13 | where 14 | T: PartialEq, 15 | { 16 | fn eq(&self, other: &Vec) -> bool { 17 | <[_] as PartialEq<[U]>>::eq(self, other) 18 | } 19 | } 20 | 21 | macro_rules! forward_mut { 22 | ($( $(#[$meta:meta])* $vis:vis fn $ident:ident(&mut self $(,$arg:ident: $ty:ty)* $(,)?) $(-> $ret:ty)?);* $(;)?) => { 23 | $( 24 | $(#[$meta])* 25 | /// 26 | #[doc = concat!("See [`", stringify!($ident), "`](alloc::vec::Vec::", stringify!($ident), ").")] 27 | $vis fn $ident(&mut self $(, $arg: $ty)*) $(-> $ret)? { 28 | // Safety: 29 | // - operation does not remove elements 30 | unsafe { self.as_mut_vec() }.$ident($($arg),*) 31 | } 32 | )* 33 | }; 34 | } 35 | 36 | /// [`Vec`] methods 37 | impl Vec { 38 | /////////// 39 | // Creation 40 | /////////// 41 | 42 | crate::map_non_empty! { 43 | /// Create a new [`NonEmpty`] heap-allocated vec 44 | new_ref(&alloc::vec::Vec) -> &Self: Self::new_ref_unchecked; 45 | /// Create a new [`NonEmpty`] heap-allocated vec 46 | new_mut(&mut alloc::vec::Vec) -> &mut Self: Self::new_mut_unchecked; 47 | } 48 | crate::transmuting! { 49 | /// Create a new [`NonEmpty`] heap-allocated vec 50 | new_unchecked(alloc::vec::Vec) -> Self; 51 | /// Create a new [`NonEmpty`] heap-allocated vec 52 | new_ref_unchecked(&alloc::vec::Vec) -> &Self; 53 | /// Create a new [`NonEmpty`] heap-allocated vec 54 | new_mut_unchecked(&mut alloc::vec::Vec) -> &mut Self; 55 | } 56 | /// Create a new [`NonEmpty`] heap-allocated vec, returning the original 57 | /// allocation if it was empty. 58 | pub fn new(src: alloc::vec::Vec) -> Result> { 59 | match src.is_empty() { 60 | false => Ok(unsafe { Self::new_unchecked(src) }), 61 | true => Err(src), 62 | } 63 | } 64 | 65 | //////////// 66 | // Utilities 67 | //////////// 68 | 69 | /// Create a [`NonEmpty`] heap-allocated vec, of a single element. 70 | pub fn of(item: T) -> Self { 71 | Self::of_with_capacity(item, 1) 72 | } 73 | /// Create a [`NonEmpty`] heap-allocated vec, of a single element, with 74 | /// capacity for `capacity` elements without (re)-allocating. 75 | pub fn of_with_capacity(item: T, capacity: usize) -> Self { 76 | let mut inner = alloc::vec::Vec::with_capacity(capacity); 77 | inner.push(item); 78 | // Safety: 79 | // - pushing the element succeeded 80 | unsafe { Self::new_unchecked(inner) } 81 | } 82 | /// Creating a [`NonEmpty`] heap-allocated vec where the first element is known. 83 | /// 84 | /// This is an convenience method, equivalent to 85 | /// ``` 86 | /// let mut it = nunny::vec!["first"]; 87 | /// it.extend(["this", "is", "the", "rest"]); 88 | /// ``` 89 | pub fn of_extending(first: T, rest: impl IntoIterator) -> Self 90 | where 91 | Self: Extend, 92 | { 93 | let rest = rest.into_iter(); 94 | let mut this = Self::of_with_capacity(first, rest.size_hint().0); 95 | this.extend(rest); 96 | this 97 | } 98 | 99 | /// Create a [`NonEmpty`] heap-allocated vec with `len` items, filled with 100 | /// [`Clone`]s of the given `value`. 101 | /// 102 | /// See also [`Self::filled_with`]. 103 | pub fn filled(value: T, len: NonZeroUsize) -> Self 104 | where 105 | T: Clone, 106 | { 107 | let mut inner = alloc::vec::Vec::new(); 108 | inner.resize(len.get(), value); 109 | // Safety: 110 | // - len is nonzero 111 | unsafe { Self::new_unchecked(inner) } 112 | } 113 | 114 | /// Create a [`NonEmpty`] heap-allocated vec with `len` items, filled with 115 | /// values returned from repeating the closure `f`. 116 | /// 117 | /// See also [`Self::filled`]. 118 | pub fn filled_with(f: F, len: NonZeroUsize) -> Self 119 | where 120 | F: FnMut() -> T, 121 | { 122 | let mut inner = alloc::vec::Vec::new(); 123 | inner.resize_with(len.get(), f); 124 | // Safety: 125 | // - len is nonzero 126 | unsafe { Self::new_unchecked(inner) } 127 | } 128 | fn check(&self) { 129 | debug_assert_ne!(self.inner.len(), 0) 130 | } 131 | 132 | /// Returns a [`std::vec::Vec`]. 133 | pub fn as_vec(&self) -> &alloc::vec::Vec { 134 | self.check(); 135 | &self.inner 136 | } 137 | /// Returns a [`std::vec::Vec`]. 138 | /// 139 | /// # Safety 140 | /// - returned vec must not be emptied through this reference 141 | pub unsafe fn as_mut_vec(&mut self) -> &mut alloc::vec::Vec { 142 | self.check(); 143 | &mut self.inner 144 | } 145 | /// Returns a [`std::vec::Vec`]. 146 | pub fn into_vec(self) -> alloc::vec::Vec { 147 | let Self { inner } = self; 148 | inner 149 | } 150 | /// Returns a [`NonEmpty`] slice. 151 | pub fn as_slice_ne(&self) -> &Slice { 152 | unsafe { Slice::new_unchecked(self.as_vec()) } 153 | } 154 | /// Returns a [`NonEmpty`] slice. 155 | pub fn as_mut_slice_ne(&mut self) -> &mut Slice { 156 | unsafe { Slice::new_mut_unchecked(self.as_mut_vec()) } 157 | } 158 | 159 | ////////////////// 160 | // Shimmed methods (rustdoc order) 161 | ////////////////// 162 | 163 | /// Returns the known non-zero length. 164 | pub fn capacity(&self) -> NonZeroUsize { 165 | self.check(); 166 | unsafe { crate::non_zero_usize(self.as_vec().capacity()) } 167 | } 168 | 169 | forward_mut! { 170 | pub fn reserve(&mut self, additional: usize); 171 | pub fn reserve_exact(&mut self, additional: usize); 172 | pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>; 173 | pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError>; 174 | pub fn shrink_to_fit(&mut self); 175 | pub fn shrink_to(&mut self, min_capacity: usize); 176 | } 177 | 178 | /// Return a [`NonEmpty`] boxed slice. 179 | pub fn into_boxed_slice(self) -> Box> { 180 | match cfg!(debug_assertions) { 181 | true => { 182 | let src = self.into_vec().into_boxed_slice(); 183 | let len0 = src.len(); 184 | let ptr = Box::into_raw(src); 185 | // Safety: 186 | // - #[repr(transparent)] 187 | let dst = unsafe { Box::from_raw(ptr as *mut Slice) }; 188 | let len1 = dst.len_ne().get(); 189 | assert_eq!(len0, len1); 190 | dst 191 | } 192 | false => { 193 | let ptr = Box::into_raw(self.into_vec().into_boxed_slice()); 194 | // Safety: 195 | // - #[repr(transparent)] 196 | unsafe { Box::from_raw(ptr as *mut Slice) } 197 | } 198 | } 199 | } 200 | 201 | /// Shortens the vector to a guaranteed-nonzero length 202 | /// 203 | /// See [`truncate`](alloc::vec::Vec::truncate). 204 | pub fn truncate(&mut self, len: NonZeroUsize) { 205 | // Safety: 206 | // - len is not zero, so vector will not be emptied 207 | unsafe { self.as_mut_vec() }.truncate(len.get()); 208 | self.check(); 209 | } 210 | 211 | /// # Safety 212 | /// - See [`set_len`](alloc::vec::Vec::set_len). 213 | pub unsafe fn set_len(&mut self, new_len: NonZeroUsize) { 214 | // Safety: 215 | // - len is not zero, so vector will not be emptied 216 | unsafe { self.as_mut_vec() }.set_len(new_len.get()); 217 | self.check(); 218 | } 219 | 220 | forward_mut! { 221 | pub fn insert(&mut self, index: usize, element: T); 222 | } 223 | 224 | /// See [`dedup_by_key`](alloc::vec::Vec::dedup_by_key). 225 | pub fn dedup_by_key(&mut self, key: F) 226 | where 227 | F: FnMut(&mut T) -> K, 228 | K: PartialEq, 229 | { 230 | // Safety: 231 | // - dedup always leaves the first element 232 | unsafe { self.as_mut_vec() }.dedup_by_key(key); 233 | self.check(); 234 | } 235 | /// See [`dedup_by`](alloc::vec::Vec::dedup_by). 236 | pub fn dedup_by(&mut self, same_bucket: F) 237 | where 238 | F: FnMut(&mut T, &mut T) -> bool, 239 | { 240 | // Safety: 241 | // - dedup always leaves the first element 242 | unsafe { self.as_mut_vec() }.dedup_by(same_bucket); 243 | self.check(); 244 | } 245 | forward_mut! { 246 | pub fn push(&mut self, value: T); 247 | pub fn append(&mut self, other: &mut alloc::vec::Vec); 248 | } 249 | 250 | // pub fn split_off(&mut self, at: NonZeroUsize) 251 | 252 | /// See [`resize_with`](alloc::vec::Vec::resize_with). 253 | pub fn resize_with(&mut self, new_len: NonZeroUsize, f: F) 254 | where 255 | F: FnMut() -> T, 256 | { 257 | // Safety: 258 | // - new_len is not zero, so vec cannot be emptied 259 | unsafe { self.as_mut_vec() }.resize_with(new_len.get(), f); 260 | self.check(); 261 | } 262 | /// Returns a [`NonEmpty`] slice. 263 | /// 264 | /// See [`leak`](alloc::vec::Vec::leak). 265 | pub fn leak<'a>(self) -> &'a mut Slice { 266 | let inner = self.into_vec().leak(); 267 | // Safety: 268 | // - originating slice is non-empty by construction 269 | unsafe { Slice::new_mut_unchecked(inner) } 270 | } 271 | forward_mut! { 272 | pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit]; 273 | } 274 | } 275 | 276 | /// Known non-empty iterator for [`Vec`]. 277 | impl Vec { 278 | pub fn into_iter_ne(self) -> NonEmpty> { 279 | NonEmpty { 280 | inner: self.into_vec().into_iter(), 281 | } 282 | } 283 | } 284 | 285 | /// [`Vec`] to [`Slice`] 286 | impl Deref for Vec { 287 | type Target = Slice; 288 | 289 | fn deref(&self) -> &Self::Target { 290 | self.as_slice_ne() 291 | } 292 | } 293 | 294 | /// [`Vec`] to [`Slice`] 295 | impl DerefMut for Vec { 296 | fn deref_mut(&mut self) -> &mut Self::Target { 297 | self.as_mut_slice_ne() 298 | } 299 | } 300 | 301 | crate::as_ref_as_mut! { 302 | for Vec as [T]; 303 | for Vec as Slice; 304 | for Vec as Self; 305 | } 306 | 307 | crate::borrow_borrow_mut! { 308 | for Vec as [T]; 309 | for Vec as Slice; 310 | } 311 | 312 | crate::slice_iter! { 313 | for Vec 314 | } 315 | 316 | mod iter { 317 | use super::*; 318 | impl IntoIterator for Vec { 319 | type Item = T; 320 | 321 | type IntoIter = alloc::vec::IntoIter; 322 | 323 | fn into_iter(self) -> Self::IntoIter { 324 | self.into_vec().into_iter() 325 | } 326 | } 327 | impl<'a, T> Extend<&'a T> for Vec 328 | where 329 | T: Copy + 'a, 330 | { 331 | fn extend>(&mut self, iter: II) { 332 | // Safety: 333 | // - append-only operation 334 | unsafe { self.as_mut_vec() }.extend(iter) 335 | } 336 | } 337 | impl Extend for Vec { 338 | fn extend>(&mut self, iter: II) { 339 | // Safety: 340 | // - append-only operation 341 | unsafe { self.as_mut_vec() }.extend(iter) 342 | } 343 | } 344 | } 345 | 346 | mod partial_eq_std { 347 | use super::*; 348 | 349 | impl PartialEq<[U]> for Vec 350 | where 351 | T: PartialEq, 352 | { 353 | fn eq(&self, other: &[U]) -> bool { 354 | <[_] as PartialEq<[_]>>::eq(self, other) 355 | } 356 | } 357 | impl PartialEq<[U; N]> for Vec 358 | where 359 | T: PartialEq, 360 | { 361 | fn eq(&self, other: &[U; N]) -> bool { 362 | <[_] as PartialEq<[_]>>::eq(self, other) 363 | } 364 | } 365 | impl PartialEq> for Vec 366 | where 367 | T: PartialEq, 368 | { 369 | fn eq(&self, other: &alloc::vec::Vec) -> bool { 370 | <[_] as PartialEq<[_]>>::eq(self, other) 371 | } 372 | } 373 | 374 | // converse 375 | //--------- 376 | 377 | impl PartialEq> for [U] 378 | where 379 | U: PartialEq, 380 | { 381 | fn eq(&self, other: &Vec) -> bool { 382 | <[_] as PartialEq<[_]>>::eq(self, other) 383 | } 384 | } 385 | impl PartialEq> for [U; N] 386 | where 387 | U: PartialEq, 388 | { 389 | fn eq(&self, other: &Vec) -> bool { 390 | <[_] as PartialEq<[_]>>::eq(self, other) 391 | } 392 | } 393 | impl PartialEq> for alloc::vec::Vec 394 | where 395 | U: PartialEq, 396 | { 397 | fn eq(&self, other: &Vec) -> bool { 398 | <[_] as PartialEq<[_]>>::eq(self, other) 399 | } 400 | } 401 | } 402 | 403 | mod cmp_std { 404 | use core::cmp::Ordering; 405 | 406 | use super::*; 407 | 408 | impl PartialOrd<[T]> for Vec 409 | where 410 | T: PartialOrd, 411 | { 412 | fn partial_cmp(&self, other: &[T]) -> Option { 413 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 414 | } 415 | } 416 | impl PartialOrd<[T; N]> for Vec 417 | where 418 | T: PartialOrd, 419 | { 420 | fn partial_cmp(&self, other: &[T; N]) -> Option { 421 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 422 | } 423 | } 424 | 425 | impl PartialOrd> for Vec 426 | where 427 | T: PartialOrd, 428 | { 429 | fn partial_cmp(&self, other: &alloc::vec::Vec) -> Option { 430 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 431 | } 432 | } 433 | 434 | // converse 435 | //--------- 436 | 437 | impl PartialOrd> for [T] 438 | where 439 | T: PartialOrd, 440 | { 441 | fn partial_cmp(&self, other: &Vec) -> Option { 442 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 443 | } 444 | } 445 | impl PartialOrd> for [T; N] 446 | where 447 | T: PartialOrd, 448 | { 449 | fn partial_cmp(&self, other: &Vec) -> Option { 450 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 451 | } 452 | } 453 | impl PartialOrd> for alloc::vec::Vec 454 | where 455 | T: PartialOrd, 456 | { 457 | fn partial_cmp(&self, other: &Vec) -> Option { 458 | <[_] as PartialOrd<[_]>>::partial_cmp(self, other) 459 | } 460 | } 461 | } 462 | 463 | mod convert_std { 464 | use crate::Error; 465 | 466 | use super::*; 467 | 468 | impl TryFrom> for Vec { 469 | type Error = alloc::vec::Vec; 470 | 471 | fn try_from(value: alloc::vec::Vec) -> Result { 472 | Vec::new(value) 473 | } 474 | } 475 | impl<'a, T> TryFrom<&'a alloc::vec::Vec> for &'a Vec { 476 | type Error = Error; 477 | 478 | fn try_from(value: &'a alloc::vec::Vec) -> Result { 479 | Vec::new_ref(value).ok_or(Error(())) 480 | } 481 | } 482 | impl<'a, T> TryFrom<&'a mut alloc::vec::Vec> for &'a mut Vec { 483 | type Error = Error; 484 | 485 | fn try_from(value: &'a mut alloc::vec::Vec) -> Result { 486 | Vec::new_mut(value).ok_or(Error(())) 487 | } 488 | } 489 | 490 | impl From> for alloc::vec::Vec { 491 | fn from(value: Vec) -> Self { 492 | value.into_vec() 493 | } 494 | } 495 | impl<'a, T> From<&'a Vec> for &'a alloc::vec::Vec { 496 | fn from(value: &'a Vec) -> Self { 497 | value.as_vec() 498 | } 499 | } 500 | } 501 | -------------------------------------------------------------------------------- /tests/from.rs: -------------------------------------------------------------------------------- 1 | //! See the documentation in `mirror_std/from.rs` for an explanation. 2 | 3 | #![allow(path_statements, clippy::no_effect)] 4 | 5 | use std::{ 6 | borrow::Cow, 7 | collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}, 8 | hash::{Hash, RandomState}, 9 | rc::Rc, 10 | sync::Arc, 11 | }; 12 | 13 | use nunny::Array; 14 | use nunny::Slice; 15 | use nunny::Vec; 16 | 17 | // const _: () = { 18 | // fn _test() { 19 | // > as From>>::from; 20 | // } 21 | // }; 22 | 23 | // const _: () = { 24 | // fn _test() { 25 | // > as From>>::from; 26 | // } 27 | // }; 28 | 29 | // const _: () = { 30 | // fn _test() { 31 | // >>::from; 32 | // } 33 | // }; 34 | 35 | // const _: () = { 36 | // fn _test() { 37 | // >>::from; 38 | // } 39 | // }; 40 | 41 | // const _: () = { 42 | // fn _test() { 43 | // >>::from; 44 | // } 45 | // }; 46 | 47 | // const _: () = { 48 | // fn _test() { 49 | // >>::from; 50 | // } 51 | // }; 52 | 53 | // const _: () = { 54 | // fn _test() { 55 | // >>::from; 56 | // } 57 | // }; 58 | 59 | // const _: () = { 60 | // fn _test() { 61 | // >>::from; 62 | // } 63 | // }; 64 | 65 | const _: () = { 66 | fn _test<'a, T>() 67 | where 68 | T: Clone, 69 | T: 'a, 70 | { 71 | > as From<&'a Slice>>::from; 72 | } 73 | }; 74 | 75 | const _: () = { 76 | fn _test<'a, T>() 77 | where 78 | T: Clone, 79 | T: 'a, 80 | { 81 | > as From<&'a Vec>>::from; 82 | } 83 | }; 84 | 85 | const _: () = { 86 | fn _test<'a, T>() 87 | where 88 | Slice: ToOwned>, 89 | T: 'a, 90 | { 91 | as From>>>::from; 92 | } 93 | }; 94 | 95 | const _: () = { 96 | fn _test<'a, T>() 97 | where 98 | T: Clone, 99 | T: 'a, 100 | { 101 | > as From>>::from; 102 | } 103 | }; 104 | 105 | const _: () = { 106 | fn _test<'a, T, const N: usize>() 107 | where 108 | T: Clone, 109 | T: 'a, 110 | { 111 | > as From<&'a Array>>::from; 112 | } 113 | }; 114 | 115 | // const _: () = { 116 | // fn _test<'data>() { 117 | // as From<&'data mut Slice>>::from; 118 | // } 119 | // }; 120 | 121 | // const _: () = { 122 | // fn _test<'data>() { 123 | // as From<&'data mut Slice>>>::from; 124 | // } 125 | // }; 126 | 127 | // const _: () = { 128 | // fn _test() { 129 | // > as From>>::from; 130 | // } 131 | // }; 132 | 133 | const _: () = { 134 | fn _test() 135 | where 136 | K: Eq + Hash, 137 | { 138 | as From>>::from; 139 | } 140 | }; 141 | 142 | const _: () = { 143 | fn _test() 144 | where 145 | K: Ord, 146 | { 147 | as From>>::from; 148 | } 149 | }; 150 | 151 | const _: () = { 152 | fn _test() 153 | where 154 | T: Clone, 155 | { 156 | > as From<&Slice>>::from; 157 | } 158 | }; 159 | 160 | const _: () = { 161 | fn _test() 162 | where 163 | T: Clone, 164 | { 165 | > as From<&Slice>>::from; 166 | } 167 | }; 168 | 169 | const _: () = { 170 | fn _test() 171 | where 172 | T: Clone, 173 | { 174 | > as From<&Slice>>::from; 175 | } 176 | }; 177 | 178 | const _: () = { 179 | fn _test() 180 | where 181 | T: Clone, 182 | { 183 | as From<&Slice>>::from; 184 | } 185 | }; 186 | 187 | const _: () = { 188 | fn _test() 189 | where 190 | T: Clone, 191 | { 192 | as From<&mut Slice>>::from; 193 | } 194 | }; 195 | 196 | const _: () = { 197 | fn _test() 198 | where 199 | T: Clone, 200 | { 201 | > as From>>>::from; 202 | } 203 | }; 204 | 205 | // const _: () = { 206 | // fn _test() { 207 | // <(T,) as From>>::from; 208 | // } 209 | // }; 210 | 211 | // const _: () = { 212 | // fn _test() { 213 | // <(T, T) as From>>::from; 214 | // } 215 | // }; 216 | 217 | // const _: () = { 218 | // fn _test() { 219 | // <(T, T, T) as From>>::from; 220 | // } 221 | // }; 222 | 223 | // const _: () = { 224 | // fn _test() { 225 | // <(T, T, T, T) as From>>::from; 226 | // } 227 | // }; 228 | 229 | // const _: () = { 230 | // fn _test() { 231 | // <(T, T, T, T, T) as From>>::from; 232 | // } 233 | // }; 234 | 235 | // const _: () = { 236 | // fn _test() { 237 | // <(T, T, T, T, T, T) as From>>::from; 238 | // } 239 | // }; 240 | 241 | // const _: () = { 242 | // fn _test() { 243 | // <(T, T, T, T, T, T, T) as From>>::from; 244 | // } 245 | // }; 246 | 247 | // const _: () = { 248 | // fn _test() { 249 | // <(T, T, T, T, T, T, T, T) as From>>::from; 250 | // } 251 | // }; 252 | 253 | // const _: () = { 254 | // fn _test() { 255 | // <(T, T, T, T, T, T, T, T, T) as From>>::from; 256 | // } 257 | // }; 258 | 259 | // const _: () = { 260 | // fn _test() { 261 | // <(T, T, T, T, T, T, T, T, T, T) as From>>::from; 262 | // } 263 | // }; 264 | 265 | // const _: () = { 266 | // fn _test() { 267 | // <(T, T, T, T, T, T, T, T, T, T, T) as From>>::from; 268 | // } 269 | // }; 270 | 271 | // const _: () = { 272 | // fn _test() { 273 | // <(T, T, T, T, T, T, T, T, T, T, T, T) as From>>::from; 274 | // } 275 | // }; 276 | 277 | // const _: () = { 278 | // fn _test() { 279 | // as From<(T, T)>>::from; 280 | // } 281 | // }; 282 | 283 | // const _: () = { 284 | // fn _test() { 285 | // as From<(T, T, T)>>::from; 286 | // } 287 | // }; 288 | 289 | // const _: () = { 290 | // fn _test() { 291 | // as From<(T, T, T, T)>>::from; 292 | // } 293 | // }; 294 | 295 | // const _: () = { 296 | // fn _test() { 297 | // as From<(T, T, T, T, T)>>::from; 298 | // } 299 | // }; 300 | 301 | // const _: () = { 302 | // fn _test() { 303 | // as From<(T, T, T, T, T, T)>>::from; 304 | // } 305 | // }; 306 | 307 | // const _: () = { 308 | // fn _test() { 309 | // as From<(T, T, T, T, T, T, T)>>::from; 310 | // } 311 | // }; 312 | 313 | // const _: () = { 314 | // fn _test() { 315 | // as From<(T, T, T, T, T, T, T, T)>>::from; 316 | // } 317 | // }; 318 | 319 | // const _: () = { 320 | // fn _test() { 321 | // as From<(T, T, T, T, T, T, T, T, T)>>::from; 322 | // } 323 | // }; 324 | 325 | // const _: () = { 326 | // fn _test() { 327 | // as From<(T, T, T, T, T, T, T, T, T, T)>>::from; 328 | // } 329 | // }; 330 | 331 | // const _: () = { 332 | // fn _test() { 333 | // as From<(T, T, T, T, T, T, T, T, T, T, T)>>::from; 334 | // } 335 | // }; 336 | 337 | // const _: () = { 338 | // fn _test() { 339 | // as From<(T, T, T, T, T, T, T, T, T, T, T, T)>>::from; 340 | // } 341 | // }; 342 | 343 | // const _: () = { 344 | // fn _test() { 345 | // as From<(T,)>>::from; 346 | // } 347 | // }; 348 | 349 | const _: () = { 350 | fn _test() { 351 | as From>>>::from; 352 | } 353 | }; 354 | 355 | const _: () = { 356 | fn _test() { 357 | > as From>>::from; 358 | } 359 | }; 360 | 361 | const _: () = { 362 | fn _test() { 363 | > as From>>::from; 364 | } 365 | }; 366 | 367 | const _: () = { 368 | fn _test() { 369 | > as From>>::from; 370 | } 371 | }; 372 | 373 | const _: () = { 374 | fn _test() 375 | where 376 | T: Clone, 377 | { 378 | as From<&Array>>::from; 379 | } 380 | }; 381 | 382 | const _: () = { 383 | fn _test() 384 | where 385 | T: Clone, 386 | { 387 | as From<&mut Array>>::from; 388 | } 389 | }; 390 | 391 | const _: () = { 392 | fn _test() { 393 | > as From>>::from; 394 | } 395 | }; 396 | 397 | const _: () = { 398 | fn _test() 399 | where 400 | T: Eq + Hash, 401 | { 402 | as From>>::from; 403 | } 404 | }; 405 | 406 | const _: () = { 407 | fn _test() 408 | where 409 | T: Ord, 410 | { 411 | as From>>::from; 412 | } 413 | }; 414 | 415 | const _: () = { 416 | fn _test() 417 | where 418 | T: Ord, 419 | { 420 | as From>>::from; 421 | } 422 | }; 423 | 424 | const _: () = { 425 | fn _test() { 426 | as From>>::from; 427 | } 428 | }; 429 | 430 | const _: () = { 431 | fn _test() { 432 | as From>>::from; 433 | } 434 | }; 435 | 436 | const _: () = { 437 | fn _test() { 438 | > as From>>::from; 439 | } 440 | }; 441 | 442 | // const _: () = { 443 | // fn _test() 444 | // where 445 | // LaneCount: SupportedLaneCount, 446 | // T: SimdElement, 447 | // { 448 | // as From>>::from; 449 | // } 450 | // }; 451 | 452 | const _: () = { 453 | fn _test() { 454 | > as From>>::from; 455 | } 456 | }; 457 | 458 | const _: () = { 459 | fn _test() { 460 | as From>>::from; 461 | } 462 | }; 463 | 464 | // const _: () = { 465 | // fn _test() 466 | // where 467 | // T: MaskElement, 468 | // LaneCount: SupportedLaneCount, 469 | // { 470 | // as From>>::from; 471 | // } 472 | // }; 473 | 474 | // const _: () = { 475 | // fn _test() 476 | // where 477 | // LaneCount: SupportedLaneCount, 478 | // T: SimdElement, 479 | // { 480 | // as From>>::from; 481 | // } 482 | // }; 483 | 484 | // const _: () = { 485 | // fn _test() 486 | // where 487 | // T: MaskElement, 488 | // LaneCount: SupportedLaneCount, 489 | // { 490 | // as From>>::from; 491 | // } 492 | // }; 493 | -------------------------------------------------------------------------------- /tests/partial_eq.rs: -------------------------------------------------------------------------------- 1 | #![allow(path_statements, clippy::no_effect)] 2 | 3 | use std::{borrow::Cow, collections::VecDeque}; 4 | 5 | use nunny::{Array, Slice, Vec}; 6 | 7 | const _: () = { 8 | fn _test() 9 | where 10 | A: PartialEq, 11 | { 12 | as PartialEq>>::eq; 13 | } 14 | }; 15 | 16 | const _: () = { 17 | fn _test() 18 | where 19 | A: PartialEq, 20 | { 21 | as PartialEq<&Slice>>::eq; 22 | } 23 | }; 24 | 25 | const _: () = { 26 | fn _test() 27 | where 28 | A: PartialEq, 29 | { 30 | as PartialEq<&mut Slice>>::eq; 31 | } 32 | }; 33 | 34 | const _: () = { 35 | fn _test() 36 | where 37 | B: PartialEq, 38 | { 39 | <&Slice as PartialEq>>::eq; 40 | } 41 | }; 42 | 43 | const _: () = { 44 | fn _test() 45 | where 46 | B: PartialEq, 47 | { 48 | <&mut Slice as PartialEq>>::eq; 49 | } 50 | }; 51 | 52 | const _: () = { 53 | fn _test() 54 | where 55 | B: PartialEq, 56 | { 57 | as PartialEq>>::eq; 58 | } 59 | }; 60 | 61 | const _: () = { 62 | fn _test() 63 | where 64 | A: PartialEq, 65 | { 66 | as PartialEq>>::eq; 67 | } 68 | }; 69 | 70 | const _: () = { 71 | fn _test() 72 | where 73 | A: PartialEq, 74 | { 75 | as PartialEq>>::eq; 76 | } 77 | }; 78 | 79 | const _: () = { 80 | fn _test() 81 | where 82 | T: PartialEq + Clone, 83 | { 84 | > as PartialEq<&Slice>>::eq; 85 | } 86 | }; 87 | 88 | const _: () = { 89 | fn _test() 90 | where 91 | T: PartialEq + Clone, 92 | { 93 | > as PartialEq<&mut Slice>>::eq; 94 | } 95 | }; 96 | 97 | const _: () = { 98 | fn _test() 99 | where 100 | T: PartialEq, 101 | { 102 | as PartialEq<&Slice>>::eq; 103 | } 104 | }; 105 | 106 | const _: () = { 107 | fn _test() 108 | where 109 | T: PartialEq, 110 | { 111 | as PartialEq<&Slice>>::eq; 112 | } 113 | }; 114 | 115 | const _: () = { 116 | fn _test() 117 | where 118 | T: PartialEq, 119 | { 120 | as PartialEq<&mut Slice>>::eq; 121 | } 122 | }; 123 | 124 | const _: () = { 125 | fn _test() 126 | where 127 | T: PartialEq, 128 | { 129 | as PartialEq<&mut Slice>>::eq; 130 | } 131 | }; 132 | 133 | const _: () = { 134 | fn _test() 135 | where 136 | T: PartialEq, 137 | { 138 | as PartialEq>>::eq; 139 | } 140 | }; 141 | 142 | const _: () = { 143 | fn _test() 144 | where 145 | T: PartialEq, 146 | { 147 | <&Slice as PartialEq>>::eq; 148 | } 149 | }; 150 | 151 | const _: () = { 152 | fn _test() 153 | where 154 | T: PartialEq, 155 | { 156 | <&mut Slice as PartialEq>>::eq; 157 | } 158 | }; 159 | 160 | const _: () = { 161 | fn _test() 162 | where 163 | T: PartialEq + Clone, 164 | { 165 | > as PartialEq>>::eq; 166 | } 167 | }; 168 | 169 | const _: () = { 170 | fn _test() 171 | where 172 | T: PartialEq, 173 | { 174 | as PartialEq>>::eq; 175 | } 176 | }; 177 | 178 | const _: () = { 179 | fn _test() 180 | where 181 | T: PartialEq, 182 | { 183 | as PartialEq<&Array>>::eq; 184 | } 185 | }; 186 | 187 | const _: () = { 188 | fn _test() 189 | where 190 | T: PartialEq, 191 | { 192 | as PartialEq<&Array>>::eq; 193 | } 194 | }; 195 | 196 | const _: () = { 197 | fn _test() 198 | where 199 | T: PartialEq, 200 | { 201 | as PartialEq<&mut Array>>::eq; 202 | } 203 | }; 204 | 205 | const _: () = { 206 | fn _test() 207 | where 208 | T: PartialEq, 209 | { 210 | as PartialEq>>::eq; 211 | } 212 | }; 213 | 214 | const _: () = { 215 | fn _test() 216 | where 217 | T: PartialEq, 218 | { 219 | as PartialEq>>::eq; 220 | } 221 | }; 222 | -------------------------------------------------------------------------------- /tests/try_from.rs: -------------------------------------------------------------------------------- 1 | //! See the documentation in `mirror_std/try_from.rs` for an explanation. 2 | 3 | #![allow(path_statements, clippy::no_effect)] 4 | 5 | // use std::{rc::Rc, sync::Arc}; 6 | 7 | use nunny::{Array, Slice, Vec}; 8 | 9 | const _: () = { 10 | fn _test<'a, T, const N: usize>() 11 | where 12 | T: 'a, 13 | { 14 | <&'a Array as TryFrom<&'a Slice>>::try_from; 15 | } 16 | }; 17 | 18 | const _: () = { 19 | fn _test<'a, T, const N: usize>() 20 | where 21 | T: 'a, 22 | { 23 | <&'a mut Array as TryFrom<&'a mut Slice>>::try_from; 24 | } 25 | }; 26 | 27 | // const _: () = { 28 | // fn _test() { 29 | // > as TryFrom>>>::try_from; 30 | // } 31 | // }; 32 | 33 | const _: () = { 34 | fn _test() { 35 | as TryFrom>>::try_from; 36 | } 37 | }; 38 | 39 | const _: () = { 40 | fn _test() 41 | where 42 | T: Copy, 43 | { 44 | as TryFrom<&Slice>>::try_from; 45 | } 46 | }; 47 | 48 | // const _: () = { 49 | // fn _test() 50 | // where 51 | // LaneCount: SupportedLaneCount, 52 | // T: SimdElement, 53 | // { 54 | // as TryFrom<&Slice>>::try_from; 55 | // } 56 | // }; 57 | 58 | const _: () = { 59 | fn _test() 60 | where 61 | T: Copy, 62 | { 63 | as TryFrom<&mut Slice>>::try_from; 64 | } 65 | }; 66 | 67 | // const _: () = { 68 | // fn _test() 69 | // where 70 | // LaneCount: SupportedLaneCount, 71 | // T: SimdElement, 72 | // { 73 | // as TryFrom<&mut Slice>>::try_from; 74 | // } 75 | // }; 76 | 77 | const _: () = { 78 | fn _test() { 79 | > as TryFrom>>>::try_from; 80 | } 81 | }; 82 | 83 | // const _: () = { 84 | // fn _test() { 85 | // > as TryFrom>>>::try_from; 86 | // } 87 | // }; 88 | 89 | const _: () = { 90 | fn _test() { 91 | > as TryFrom>>::try_from; 92 | } 93 | }; 94 | --------------------------------------------------------------------------------